Entity Framework 4.1– beware of the DbSet.Find method
One of the new features of Entity Framework 4.1 is the DbContext API which is basically a simplification of the ObjectContext API, and is intended to make your life a bit easier.
In this new API you can find the DbSet.Find method which according to MSDN does the following:
“Uses the primary key value to attempt to find an entity tracked by the context. If the entity is not in the context then a query will be executed and evaluated against the data in the data source, and null is returned if the entity is not found in the context or in the data source…”.
The section I underlined (“evaluated against the data in the data source”) is the one that you should beware of - the inner implementation of the Find() method creates a query that runs in the database and searches the entity set for the entity you want to find according to the ID which is passed to the method.
Now what’s wrong with the sentence I just wrote? it searches for the entity according to the ENTITY SET, not the entity type! This is a snippet from the implementation (using ILSpy):
If your model uses simple entity types, with no inheritance between them, you won’t have a problem with the Find() method, but… if your model contains an inheritance tree, and you try to use the method to find a derived type, then the method will create a query that searches the entire class hierarchy from the base type downwards – in all the child tables, instead of looking into the specific entity type’s table. This type of query will at the minimum take more time to execute because of all the joins between the tables, and in the worst case scenario – if you have many entity types mapped to different tables, it will crash because it will try to created a nested query with too many levels (check the “Query Complexity” section in the Performance Considerations for EF in MSDN).
What can you do? if you have a base type for all your entities, first ask yourself why you need the base type, since it usually creates problems with Entity Framework – there are several ways to overcome this, either by using interfaces, or by using base types not mapped to the EF model. If you do need the inheritance and do want to use the Find method’s technique of first looking in the loaded entities before searching the database, just write an extension method for the DbSet that first searches the loaded entities by looking in the DbSet.Local collection and if the entity isn’t found, run a SingleOrDefault query in the database.