I've heard that you should disable the lazy loading feature of EF in web applications. (ASP.NET). Here and here, for starters.
Now I'm really confused here because I always thought that lazy loading should always be enabled because it prevents unnecessary data fetching from the database. So, now my question is: Is it generally a better idea to disable lazy loading in web apps in terms of performance. If yes, could you explain why?
You should always use lazy loading for the images below the fold. As we explained, lazy loading will reduce the real and perceived loading time. User experience will benefit from it — and you users will thank you.
Lazy loading is the process whereby an entity or collection of entities is automatically loaded from the database the first time that a property referring to the entity/entities is accessed. Lazy loading means delaying the loading of related data, until you specifically request for it.
The benefits of lazy loading include: Reduces initial load time – Lazy loading a webpage reduces page weight, allowing for a quicker page load time. Bandwidth conservation – Lazy loading conserves bandwidth by delivering content to users only if it's requested.
There are options to disable Lazy Loading in an Entity Framework. After turning Lazy Loading off, you can still load the entities by explicitly calling the Load method for the related entities. There are two ways to use Load method Reference (to load single navigation property) and Collection (to load collections), as shown below.
Manually loading data You can manually control which property to load in two different ways: during an Entity Request (Eager Loading) or with a single Property Load. Property Loading If you choose Property Loading, all you need to do is to use the Load() method supplied by the entity framework:
For example, the Student entity contains the StudentAddress entity. In the lazy loading, the context first loads the Student entity data from the database, then it will load the StudentAddress entity when we access the StudentAddress property as shown below. The code shown above will result in two SQL queries.
Lazy loading is enabled by default, but you can disable lazy loading for a particular entity or a context. Do not make a navigational property virtual, if you want to turn off lazy loading for a particular property. If you want to turn off lazy loading for all entities in the context, set its configuration property to false.
Disabling lazy loading will prevent Select N+1 performance problems as well as recursive serialization bail-outs, however it replaces those with another artifact, null references.
When working with web applications I do not disable lazy loading, but rather I ensure that my controllers/APIs do not return entities, but rather they return ViewModels or DTOs. When you adopt using POCO classes to feed your views just the amount of data, and the structure they need, and use .Select()
or Automapper's ProjectTo<TViewModel>()
to populate them via deferred execution, you avoid the need to worry about lazy load, and introduce better overall performance and resource usage for your application. Technically, using this approach, lazy loading can be disabled, so it's not really an argument for or against disabling it but rather that the mere act of disabling lazy loading won't make your web application "better".
Adopting ViewModels offers a number of advantages:
So for me, the issue with web applications isn't to lazy load or not, it's simply to avoid passing entities to the client. I see far, far too many "examples" out there where they pass entities around. I don't consider it a healthy pattern.
As an example, using a view model the first question is "What data does my view actually need?" So given a product and a product category, if I want to send a product entity, but I also need the product category name for instance we hit a nasty problem if our product category contains a collection of products, and each of those products has a category. When we pass our product to the serializer it's going to hit that cyclic reference and it's either going to bail out (leaving a reference or collection #null) or it is going to throw an exception. But working through the Select N+1 we would iterate over the Product properties, hit the ProductCategory reference, then "SELECT FROM ProductCategory WHERE ProductCategoryID = 3". Then as we iterate over that product category, we hit another reference, and that is another SELECT.... and so-forth down the chain.
By using a view model you limit the data you want to retrieve to just what the view needs. I create a Product View-model which outlines the fields I care about, irregardless of where the data comes from. If I want something like a product, it's name, and it's category name:
public class ProductViewModel
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public string CategoryName { get; set; }
}
then to load it:
var viewModel = context.Products
.Where(x => x.ProductId == productId)
.Select(x => new ProductViewModel
{
ProductId = x.ProductId,
ProductName = x.Name,
CategoryName = x.Category.Name
}).Single();
Done. No lazy loads or eager loads required. This produces a single query that returns a single record with just the 3 columns we need. (Rather than the entire Product record, and it's Product Category)
As requirements get more complex we can introduce a view model hierarchy, but we can continue to flatten down the related data based on what the view actually needs. In some cases it might mean selecting into an anonymous type then translating those results into view models where we need to use functions etc. that EF cannot translate down to SQL. The approach is a powerful and fast alternative to relying on loading entities, but requires attention at the start to understand what the end consumer (view/API) will need from the data.
In web apps you have a lot of concurrent requests from different users, each request is being handled pretty fast (at least it should be), so you want to reduce number of DB calls during each request, because each DB request happens via network. With Lazy loading, every time you using relational property, it makes another call to DB to load this related data to your entity collection. So during one http request you can make a lot of additional requests to DB in such way, what from the performance prospective really hurts your application. In normal scenarios when you initially fetching your data from DB you already would know what related data do you need, so you can use eager loading of related entities to load everything that you need in one request to DB to handle particular http request.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With