Reputation: 2716
I have an ASP.NET MVC application utilizing Entity Framework for the data layer.
In one of my methods I retrieve the seasonal availability data for a product, and afterwards, the best tax rate for the product.
public ProductList FetchProductSearchList(ProductSearchCriteria criteria)
{
...
var avail = ProductAvailabilityTemplate.Get(criteria.ProductID);
...
var tr = TaxRate.BestMatchFor(criteria.ProductID, criteria.TaxCode);
...
}
In the data layer for ProductAvailabilityTemplate.Get, I had been optimizing the performance of my LINQ code. In particular, I had set ctx.ObjectContext.ContextOptions.LazyLoadingEnabled = false;
to prevent EF from loading some entities (via navigation properties) that I don't need in this scenario.
However, once this change was made I noticed that my TaxRates weren't loading fully, because ctx.ObjectContext.ContextOptions.LazyLoadingEnabled
was still false in my Tax data layer code. This meant that an entity linked to TaxRate via a navigation property wasn't being loaded.
To overcome this problem I simply set ctx.ObjectContext.ContextOptions.LazyLoadingEnabled = true;
in the Tax data layer method, but I am concerned that an unrelated change could cause a problem like this. It seems that you can't safely disable lazy loading for one feature without potentially affecting the operation of whatever is called afterwards. I am tempted to remove all navigation properties, disable lazy loading, and use good old fashioned joins to load exactly what I need for each data layer call, no more no less.
Would welcome any advice.
Upvotes: 4
Views: 1042
Reputation: 107247
It's a trade off:
Lazy Loading
virtual
properties with proxies)DbContext
to be longer lived, for the duration of all data accesses.Eager Loading
DbContexts
FWIW, I've generally done prototype work with Lazy Loading enabled, to get software to a demonstrable state, and once the data access patterns stabilize, then switch off Lazy Loading and move to explicitly Include
d references. A few Unit Tests checking for null references will also do wonders at this point. I am loathe to deliver a production system with Lazy Loading still enabled, as there is an element of non-determinism (e.g. difficult to fully test), and the need to return to the DB for further data will hurt performance.
Either way, I wouldn't switch off all Navigation and do explicit Joins - you are losing the power of navigability that an ORM provides. When you switch out of Lazy Loading, simply explicitly define the entities to be eager loaded with applicable Includes
Upvotes: 3
Reputation: 2233
I was fond of lazy loading when I started using EF, but after a while I realized that it was affecting performance since it effectively disables joins and pulls all subdata in separate queries even if you need to consume it all at once.
So now I'm rather using Includes to eagerly load the sub-entities that I'm interested in. You could also do this somewhat dynamic, for instance by providing a includeDetails parameter:
public IEnumerable<Customer> LoadCustomersStartingWithName(string name, bool includeDetails)
{
using (var db = new MyContext())
{
var customers = db.Customers;
if (includeDetails)
customers = customers.Include(x => x.Orders).Include(x => x.ContactPersons);
customers = customers.Where(x => x.Name.StartsWith(name));
return customers;
}
}
For the code to work in EF6, you would also need to include
using System.Data.Entity;
at the top of the class
Upvotes: 2