One of the most interesting Entity Framework features is the Lazy Load function, which allows a deferred data load of your related entities, meaning that DB data won't be loaded until you specifically request it.
To better understand how it's working, let's take these sample Entity classes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public class Student { public Student() { } public int StudentId { get; set; } public string StudentName { get; set; } public virtual StudentAddress StudentAddress { get; set; } public virtual ICollection<Teacher> Teachers { get; set; } } public class StudentAddress { [Key, ForeignKey("Student")] public int StudentId { get; set; } public string Address1 { get; set; } public string Address2 { get; set; } public string City { get; set; } public int Zipcode { get; set; } public string State { get; set; } public string Country { get; set; } public virtual ICollection<StudentAddressDetail> StudentAddressDetails { get; set; } public virtual Student Student { get; set; } } |
We can notice that the StudentAddress property of the Student class is referring to another Entity (StudentAddress), which is also related to a specific DB table. If we request a list of Students with LazyLoading enabled, the data provider will get all of our students from the DB but each StudentAddress property won't be loaded until the property will be explicitly accessed.
1 2 3 4 5 6 7 8 9 |
using (var ctx = new SchoolDBEntities()) { // Loads only the students IList<Student> sList = ctx.Students.ToList<Student>(); Student s = sList[0]; // Loads this StudentAddress for this specific user only (with a separate SQL query) StudentAddress a = s.StudentAddress; } |
Disable Lazy Loading
In Entity Framework 4 and beyond Lazy Loading is enabled by default. We can disable it globally, on DbContext level, or selectively, on per-property level.
To disable it globally you need to set the DbContext's LazyLoadingEnabled property to false in the object's constructor:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
using System; using System.Data.Entity; using System.Data.Entity.Infrastructure; using System.Data.Entity.Core.Objects; using System.Linq; public partial class SchoolDBEntities : DbContext { public SchoolDBEntities(): base("name=SchoolDBEntities") { this.Configuration.LazyLoadingEnabled = false; } } |
To disable it on per-property level, all you need to do is to make the property non-virtual. For example, we could modify the Student class in the following way:
1 2 3 4 5 6 7 8 9 10 11 |
public class Student { public Student() { } public int StudentId { get; set; } public string StudentName { get; set; } // non-virtual property - lazy load disabled public StudentAddress StudentAddress { get; set; } // non-virtual property - lazy load disabled public ICollection<Teacher> Teachers { get; set; } } |
IMPORTANT: You could easily think that, once you disable Lazy Loading, the framework will auto-load each and every related property: it won't. Don't worry, it's a good thing! You don't want your DB to be automatically wasted on each Entity query request. On the opposite, disabling Lazy Loading means that you will have to manually handle each related property loading. Let's see how you can do that.
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:
1 2 3 4 5 6 7 8 |
using (var ctx = new SchoolDBEntities()) { // Loads the student with Primary Key 1 Student s = ctx.Students.Find(1); // Load the student's related StudentAddress ctx.Entry(s).Reference(i => i.StudentAddress).Load(); } |
The method can ben used to load either one-to-one and one-to-many relationships. For example, we could request the loading of the Teachers collection property in the following way:
1 2 3 4 5 6 7 8 |
using (var ctx = new SchoolDBEntities()) { // Loads the student with Primary Key 1 Student s = ctx.Students.Find(1); // Load the student's related StudentAddress ctx.Entry(s).Collection(i => i.Teachers).Load(); } |
Eager Loading
The Eager Loading function is useful when you want to load the main Entity (or Entity collection) togheter with its (theirs) related entities right from the start, possibly using a single query command. In order to use that you need to use the Include() method in the following way:
1 2 3 4 5 6 |
using (var ctx = new SchoolDBEntities()) { // Loads the students AND all related StudentAddress using Eager Loading IList<Student> sList = ctx.Students.Include(s => s.StudentAddress).ToList<Student>(); Student s = sList[0]; } |
IMPORTANT: If you can't find the Include() method, check that you added the System.Data.Entity namespace.
You can also use Eager Loading to load nested, multi-level properties. For example, we could load the StudentAddressDetails collection property of each StudentAddress item (cfr. the StudentAddress class definition above) in the following way:
1 2 3 4 5 6 |
using (var ctx = new SchoolDBEntities()) { // Loads the students AND all related StudentAddress AND all related StudentAddressDetails using Eager Loading IList<Student> sList = ctx.Students.Include(s => s.StudentAddress.StudentAddressDetails).ToList<Student>(); Student s = sList[0]; } |
And so on.
That's it for now: happy coding!
Hi Ryan, thanks for an awesome explanation and nice and easy to understand examples. Could you please add vk.com share button to your website? Cheers
Hi Ryan!
Thanks, article great!
I have proplem this. Lazy load init all object when Application running first and it very slow. How to resolve for proplem this?
Hello, Lazy Load won’t init all objects when the Application starts: it actually does quite the opposite, i.e. load items as they’re needed.
Of course if you have a huge home page with a lot of nested contents, Lazy Load won’t be of any use because you *will* need them all when you load it the first time. If that’s the case, you should probably optimize your EF relationships and/or LINQ/Lambda expressions to retrieve DB data more efficiently, which is something you can often do better with (selective) Eager Loading.
You should run a benchmark tool to measure how much time you need for each EF call and then pinpoint the slow query(es). If you want, I can post a nice helper class I’m using to do just that: it’s basically a time tracker where you can define multiple “laps” and show them all at the end of the response, i.e. inside a view.
Please let me know.
Dear @Dark, I happy, when you can share it with me.
Real, when i use EF, first application running is very slow.
Thanks Dark!
Here it is: I wrote the post just for you :)
https://www.ryadel.com/en/timetracker-c-sharp-class-to-measure-source-code-execution-time/
Try to use it to find your performance bottleneck.
Thanks @v2Dark:disqus!
Hey,
If you define your navigation property virtual, Entity Framework will at runtime create a new class (dynamic proxy) derived from your class and uses it instead of your original class. This new dynamically created class contains logic to load the navigation property when accessed for the first time. This is referred to as “lazy loading”. It enables Entity Framework to avoid loading an entire tree of dependent objects which are not needed from the database.
Thanks