Lazy Loading (4): EntityFramework

In this series of articles, we discuss Lazy Loading and related. There is no Lazy Loading Category on this site; we put the articles in the LINQ category because the behavior of Lazy Loading is based on or related to LINQ.

Introduction

This article will discuss Lazy Loading for JavaScript and give a demo to demonstrate the Lazy Loading that will enable the images to load as the site visitors scroll down the page decreasing the page load time. The content of the article is

  • Introduction
  • A - Lazy Loading for C# Entiry Framework
  • B - Demo Environment Setup
  • C - Demo
    • Lazy Loading
    • Eager Loading
    • Explicitly Loading
  • D - Turning Off Lazy Loading
  • E - Performance Consideration

A - Lazy Loading for C# Entity Framework

In this series of articles, in the previous two articles, we discussed lazy loading for HTML and JavaScript. They are both for loading content, such as photos. In this article, we discuss the Entity Framework Lazy loading, which is most likely to deal with database loading.

Lazy Loading for entity framework means the related entities are not loaded, until we iterate through them or bind them the data. By default, LINQ to SQL loads the related entities using Lazy Loading.

 

In this database table, there is a one-to-many relationship between Department and Course entities. A Department can have 1 or more courses open. When the departments are loaded, the related entities (Course entities) are not loaded. Course entity is only loaded when we iterate through the objects belonging to a given department.

B - Demo Environment Setup

In the database ContosoUniversity, Table Department and Table Course are one too Many relationships:

This is the Department Table:

This is the Course Table:

We make an entity to examine the relationship between these two tables:

For a .NET Framework project: right Click Project => Add New Item => Data => ADO.NET Entity Data Model

In the Entity Data Model Wizard: Click EF Designer from the Database.

Choose data source (connection):

Choose tables: Department & Course:

Get Entity Diagram: 

C - Demo

There are several ways that the Entity Framework can load related data into the navigation properties of an entity:

  • Lazy loading. When the entity is first read, related data isn't retrieved. However, the first time you attempt to access a navigation property, the data required for that navigation property is automatically retrieved. This results in multiple queries sent to the database — one for the entity itself and one each time that related data for the entity must be retrieved. The DbContext class enables lazy loading by default.

When code runs at Line 36, Query all Department rows:

we may detect it by running SQL Profiler at Line37 (after LIne 36): only Department Tables were SELECT:

while after running Line 38 (say, the first loop), the SQL Server Profiler will detect the Course Table SELECT for specific Department ID --- the result is deferred from getting the Department table 

This process is equivalent to the following:

  • Eager loading. When the entity is read, related data is retrieved along with it. This typically results in a single join query that retrieves all of the data that's needed. You specify eager loading by using the Include method.

When code runs at Line 36, Query all Department rows and related Course rows:

The SQL Server Profiler will show the result like this

This process is equivalent to the following:

  • Explicit loading. This is similar to lazy loading, except that you explicitly retrieve the related data in code; it doesn't happen automatically when you access a navigation property. You load related data manually by getting the object state manager entry for an entity and calling the Collection.Load method for collections or the Reference.Load method for properties that hold a single entity. (In the following example, if you wanted to load the Administrator navigation property, you'd replace Collection(x => x.Courses) with Reference(x => x.Administrator).) Typically you'd use explicit loading only when you've turned lazy loading off.

The process is exactly the same as lazy loading, except the loading at Lione 57 is explicitly triggered by the Load() Method:

The following in SQL is the same as lazy loading:

at Line54 (after LIne 54): only Department Tables were SELECT:

while after running Line 57 (say, the first loop), the Course Table SELECT for specific Department ID by explicityly loading: 

Because they don't immediately retrieve the property values, lazy loading, and explicit loading are also both known as deferred loading.

D - Turning Off Lazy Loading

As we mentioned previously:

  • By default, LINQ to SQL loads the related entities using Lazy Loading.

  • For the Entity Framework, The DbContext class enables lazy loading by default.

Now we discuss how to disable lazy loading, such as before serialization

public class BloggingContext : DbContext
{
    public BloggingContext()
    {
        this.Configuration.ProxyCreationEnabled = false;
    }  

    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
}
  • Here are some other ways to disable lazy loading:
    • For specific navigation properties, omit the virtual the keyword when you declare the property.
    • For all navigation properties, set LazyLoadingEnabled to false Put the following code in the constructor of your context class:
this.Configuration.LazyLoadingEnabled = false;

E - Performance considerations

Using Eager Loading:

If you know, you need related data for every entity retrieved. Eager loading often offers the best performance because a single query sent to the database is typically more efficient than separate queries for each entity retrieved.

For example, in the above examples, suppose that each department has ten related courses. The eager loading example would result in just a single (join) query and a single round trip to the database. The lazy loading and explicit loading examples would both result in eleven queries and eleven round trips to the database. The extra round trips to the database are especially detrimental to performance when latency is high.

Using Lazy Loading:

On the other hand, in some scenarios, lazy loading is more efficient. Eager loading might cause a very complex join to be generated, which SQL Server can't process efficiently. Or if you need to access an entity's navigation properties only for a subset of a set of the entities you're processing, lazy loading might perform better because eager loading would retrieve more data than you need.

Testing for Choosing:

If performance is critical, it's best to test performance both ways in order to make the best choice.

Lazy loading can mask code that causes performance problems. For example, code that doesn't specify eager or explicit loading but processes a high volume of entities and uses several navigation properties in each iteration might be very inefficient (because of many round trips to the database). An application that performs well in development using an on-premise SQL server might have performance problems when moved to Azure SQL Database due to the increased latency and lazy loading. Profiling the database queries with a realistic test load will help you determine if lazy loading is appropriate. For more information, see Demystifying Entity Framework Strategies: Loading Related Data and Using the Entity Framework to Reduce Network Latency to SQL Azure.

References