Lazy Loading in Entity Framework 4

Like the debate for FK Association, many customers persist that Lazy Loading should be a necessity for an ORM like EF, while others believe it is evil. Also in EFv1, Lazy Loading is not available. Fortunately, thanks to EF team’s effort again, Lazy Loading becomes the default option in EF4, as we already have in LINQ to SQL. Of course, we can still use Eager Loading and Explicit Loading as our wish. Let’s see how they work in EF4.

image

We first create an EDM with two entities: Department and Course.

Lazy Loading

Right click any blank area of the EDM designer, we see the ConceptualEntityModel properties of the EDM. Among the properties, there is one property named Lazy Loading Enabled which is by default set to True.

image

With Lazy Loading Enabled, the constructors of our ObjecConntext look like:

   1:     /// <summary>
  2:     /// Initializes a new LazyLoadingEntities object using 
  3:     /// the connection string found in the 'LazyLoadingEntities'
  4:     ///  section of the application configuration file.
  5:     /// </summary>
  6:     public LazyLoadingEntities() : 
  7:     base("name=LazyLoadingEntities", "LazyLoadingEntities")
  8:     {
  9:         this.ContextOptions.LazyLoadingEnabled = true;
 10:         OnContextCreated();
 11:     }
 12: 

Let’s see how Lazy Loading works.

   1:     using (LazyLoadingEntities context = new LazyLoadingEntities())
  2:     {
  3:     // Lazy loading is enabled dy default in EF4, so turn it off 
  4:     // to use eager loading later
  5:         context.ContextOptions.LazyLoadingEnabled = false;
  7:     // Query the department entities which Budget is not NULL
  8:     // Here we use the .Include() method to eager load the related
  9:     // course entities
 10:         var departments = from d in context.Departments.Include("Courses")
 11:         where d.Budget != null
 12:         select d;
 13:         foreach (var department in departments)
 14:         {
 15:             Console.WriteLine("Department: {0}", department.Name);
 16:             Console.WriteLine("Courses:");
 17:     // The related course entities has been already loaded
 18:     // Note: for eager loading, there will be only one
 19:     // database call to load the department and corresponding 
 20:     // course entities
 21:             foreach (var course in department.Courses)
 22:             {
 23:                 Console.WriteLine(course.Title);
 24:             }
 26:             Console.WriteLine();
 27:         }
 28:     }

For the sake of this example, assume that we have 5 departments and 10 courses for 4 departments among the 5 departments. From the query results in the SQL Server Profiler, there is 1 query to retrieve the Departments and 4 individual queries for each of the 4 Departments.

image

Last week, I heard that IntelliTrace in VS2010 Ultimate can also trace the SQL execution of our application, like the following image indicates.

image

Eager Loading

Eager Loading is implemented by the Include method which specifies the related objects to include in the query results. To use Eager Loading in EF4, we need to turn of the default Lazy Loading by setting the Lazy Loading Enabled property to False or programmatically set the ObjectContextOptions.LazyLoadingEnabled = false.

Let’s see how Eager Loading works.

   1:     using (LazyLoadingEntities context = new LazyLoadingEntities())
  2:     {
  3:     // Lazy loading is enabled dy default in EF4, so turn it off 
  4:     // to use eager loading later
  5:         context.ContextOptions.LazyLoadingEnabled = false;
  6: 
  7:     // Query the department entities which Budget is not NULL
  8:     // Here we use the .Include() method to eager load the related
  9:     // course entities
 10:         var departments = from d in context.Departments.Include("Courses")
 11:         where d.Budget != null
 12:         select d;
 13:         foreach (var department in departments)
 14:         {
 15:             Console.WriteLine("Department: {0}", department.Name);
 16:             Console.WriteLine("Courses:");
 17:     // The related course entities has been already loaded
 18:     // Note: for eager loading, there will be only one
 19:     // database call to load the department and corresponding
 20:     // course entities
 21:             foreach (var course in department.Courses)
 22:             {
 23:                 Console.WriteLine(course.Title);
 24:             }
 25:             Console.WriteLine();
 26:         }
 27:     }

From the SQL commands tracked in SQL Server Profiler, only 1 query is executed to retrieve all the related Departments and Courses.

image

Trace result in IntelliTrace:

image

Explicit Loading Explicit Loading is implemented by calling EntityCollection.Load or EntityReference.Load to retrieve the related entities. Similar with the Eager Loading, we need to turn off the default Lazy Loading in EF4.

   1:     using (LazyLoadingEntities context = new LazyLoadingEntities())
  2:     {
  3:     // Lazy loading is enabled dy default in EF4, so turn it off 
  4:     // to use explicit loading later
  5:         context.ContextOptions.LazyLoadingEnabled = false;
  6:     // Query the department entities which Budget is not NULL
  7:         var departments = from d in context.Departments
  8:                           where d.Budget != null
  9:         select d;
 10:         foreach (var department in departments)
 11:         {
 12:             Console.WriteLine("Department: {0}", department.Name);
 13:             Console.WriteLine("Courses:");
 14:     // Explicit load the related courses entities if they
 15:     // are not loaded yet
 16:     // Note: here for each department, there will be a 
 17:     // seperate database call to load the course entities
 18:             if (!department.Courses.IsLoaded)
 19:             {
 20:                 department.Courses.Load();
 21:             }
 22:             foreach (var course in department.Courses)
 23:             {
 24:                 Console.WriteLine(course.Title);
 25:             }
 26:             Console.WriteLine();
 27:         }
 28:     }
 29: 

The SQL commands that are executed here are similar with what we saw in the Lazy Loading test.

Discussion

Actually, I think Lazy Loading, Eager Loading and Explicit Loading are for different scenarios. Lazy Loading and Explicit Loading are in one kind while Eager Loading is the opposite. EF4 helps us to implement the Explicit Loading logic to retrieve the related entities if necessary, which becomes Lazy Loading. So I believe Lazy Loading and Explicit Loading offer the same performance benefits and challenges. For the Eager Loading, the benefit is that we only use one query to get all the related entities, which means only one database connection and one network trip are needed here. However, the single resultset can be really large and the single query structure can be very complicated and expensive (with many JOINs).

Like the folks who support Lazy Loading, I second that it should be a feature of an ORM. I am very glad to see that Lazy Loading is now implemented in EF4, because it makes the entity world more flexible. J

All the sample codes in this post can be found in the samples CSEFLazyLoading (C#) and VBEFLazyLoading (VB.NET) in All-In-One Code Framework which is an open-source project delineating the framework and skeleton of Microsoft development techniques.

Additional references

Loading Related Objects (Entity Framework) https://msdn.microsoft.com/en-us/library/bb896272.aspx

How to: Use Lazy Loading to Load Related Objects (Entity Framework) https://msdn.microsoft.com/en-us/library/dd456846.aspx

How to: Use Query Paths to Shape Results (Entity Framework) https://msdn.microsoft.com/en-us/library/bb738449.aspx

How to: Explicitly Load Related Objects (Entity Framework) https://msdn.microsoft.com/en-us/library/bb896249.aspx