Oooh laa laa, my favorite so far.
One of my most oft-repeated bits of EF guidance is that “a query’s job is to execute”.
If you write a query such as
Any time you do soomthing with myquery, such as call ToList or Count or bind it to a databinding control, it will be exeucted on the database.
Too many times developers will write that query and execute it and then a little later do something like:
hoping to find out how many customers are in memory.
But context.Customers is a query and a query’s job is to execute, so it will not look in memory. It will look in the database.
Instead you need to look in the ObjectStateManager, pull out the existing objectStateEntries and then navigate back to the in-memory objects with the ObjectStateEntry.Entity property. I even have a clever extension method (yes I was very proud of myself when I thought of it!) that is used in my book samples called ManagedEntities which will do this for you.
Here it is as a regular method, not an extension method.
public IEnumerable<T> ManagedEntities<T>()
var oses = ObjectStateManager.GetObjectStateEntries();
return oses.Where(entry => entry.Entity is T)
.Select(entry => (T)entry.Entity);
Note that my ManagedEntities method also leverages another one of my custom extension methods which is an overload of GetObjectStateEntries. I leaned on a lot of deep knowledge of EF to write this.
But now in CTP5, the DbContext has a method that does what my ManagedEntities method. It’s called local.
- var context = new AWEntities();
- var customer = context.Customers.Include("Orders").Take(10).ToList();
- var orderEntries = context.Orders.Local;
The 3rd line of code will pull out all of the orders that were put into memory with the previous line of code.
Local makes sense. There will still be a million and one calls to context.ORders by developers who don’t realize that that goes to the database but at least Local is pretty discoverable. More importantly it is a thousand times easier than going through the ObjectStateManager…which is (and should be) plumbing.