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.
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.
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.
Last week, I heard that IntelliTrace in VS2010 Ultimate can also trace the SQL execution of our application, like the following image indicates.
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.
Trace result in IntelliTrace:
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
Comments
Anonymous
November 29, 2010
I think it was interessant to have a lazy loading like this .. var departments = from d in context.Departments.Include(x => x.Courses.Where(x => x.CourseTitle == "401")).Where(x=> x.DeptNo = 2); For me I have many scenario like that.. Julien.Anonymous
January 11, 2011
Interesting post. But I just recognized that the code for Lazy Coding can't be right. It is the same as for the Eager Loading... Could you please correct that? ThanksAnonymous
November 27, 2012
Lazy loading code needs your attention, Please correct that!Anonymous
November 28, 2012
I found a video here www.youtube.com/watchAnonymous
December 08, 2012
Lazy loading true vs false doesn't seem to have any effect. Related entities seem to be loaded regardless of this setting.Anonymous
March 06, 2013
Lazy loading true vs false doesn't seem to have any effect. Related entities seem to be loaded regardless of this setting.