Lazy Loading is a technique in which we have the option to load related data of a record in the future. Suppose we have two models, students and contacts, where each student can have several contacts, that is, there is a one to many relationship between students and contacts. In the case of our Student and Contact models, we can load the student data now, and, if we need it, in the future, we can load the data from the related Contacts.
The key to this technique is that it is efficient from the point of view of the data load, since it only loads the related data if we need it. This is different from the eager loading technique, where we always load related data.
The data related to the technique of lazy loading is brought from the database at the moment we try to access it.
The Student and Contact models that we are going to use for this post are:
public class Student { public int Id { get; set; } public string Name { get; set; } public List<Contact> Contacts { get; set; } } public class Contact { public int Id { get; set; } public string Name { get; set; } public int StudentId { get; set; } public Student Student { get; set; } }
Configuring Lazy Loading
Let’s first configure lazy loading in our project. The first thing you should do is install the Microsoft.EntityFrameworkCore.Proxies package.
Then, if you are not using ASP.NET, then we have to use the UseLazyLoadingProxies function in our OnConfiguring method of our Data Context class (the one that inherits from DbContext):
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer("[ConnectionString]") .UseLazyLoadingProxies(); }
If you are using ASP.NET, you do not need to do what we did above, but you configure the Lazy Loading in your Startup class, in the ConfigureServices method:
services.AddDbContext<ApplicationDbContext>(x => x.UseSqlServer(Configuration.GetConnectionString("myConnectionString")) .UseLazyLoadingProxies());
We must also make a configuration on our model to be able to use the lazy load. This configuration can be done in different ways, one of them is to place the navigational properties that we want to use with lazy loading as virtual (In C #, when a property is marked as virtual, it means that it can be overwritten by a derived class). We will then mark our navigational property of the Student model as virtual:
public virtual Student Student { get; set; }
We must also mark the navigational property that is in the Contact model as virtual:
public virtual List<Contact> Contacts { get; set; }
There is another way to configure a model to use the lazy load, and it is by placing a constructor in that model which receives an ILazyLoader[1] . The way you configure the model makes no difference in its use.
Using Lazy Loading
Let’s see how to use lazy loading:
using (var context = new ApplicationDbContext()) { var students = context.Students.FirstOrDefault(); // The following line loads the contacts students.Contacts.ToList(); // This is another way of loading the contacts foreach (var contact in students.Contacts) { } }
Remember that we said that the related data is brought from the database when we try to access it. In code, this means that if we “touch” the navigational property, then at that moment EF Core will load the related data. The first way in which we touch the navigational property Contacts is by making a simple ToList on the Contacts property. The second way is trying to access Contacts records with a foreach. Both ways have the same result.
It is important to take into account that EF Core is only going to perform the related load of data once. Therefore, if you execute the previous code as is, the data of the contacts will only be loaded the first time you try to work with the Contacts property, on the second occasion the data will already be loaded, so EF Core will not try to search for it again in the database.
Conclusion
We can use Lazy Loading to load data related to Entity Framework Core 2.1 only in case we need such data.
[1] EF Core docs talk about this: https://docs.microsoft.com/en-us/ef/core/querying/related-data#lazy-loading-without-proxies