Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should Entity Framework lazy loading be disabled in web apps?

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?

like image 586
Arad Avatar asked Jan 27 '19 07:01

Arad


People also ask

Should I enable lazy loading?

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.

Why do we use lazy loading in Entity Framework?

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.

Is lazy loading good for performance?

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.

How to disable lazy loading in an Entity Framework?

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.

How do I manually load data in Entity Framework?

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:

How to lazy load the student entity in a context?

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.

How do I enable or disable lazy loading?

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.


2 Answers

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:

  • Avoids lazy load calls or unexpected #null references.
  • Sends only the data needed by the view/consumer, and nothing more. (Less data over the wire, and less information for hackers with debugging views.)
  • Builds efficient, index-able queries to the database server.
  • Provides a place for computed columns that won't trip up EF.
  • Helps reduce security issues (unexpected entity modifications) on the trip back. (A view model cannot simply be re-attached and committed to DB by a lazy developer)

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.

like image 195
Steve Py Avatar answered Oct 05 '22 05:10

Steve Py


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.

like image 27
Amir Arbabian Avatar answered Oct 05 '22 06:10

Amir Arbabian