Lazy Loading in Entity Framework Core

Lazy loading in Entity Framework Core allows EF Core to retrieve related data whenever it needs it. The EF Core retrieves the related data behind the scene, whenever we access the navigational property. The EF Core does not support Lazy Loading out of the box. Hence to use it we need to enable it. There are two ways you can enable Lazy Loading. One using the Proxies Package and the one by injecting ILazyLoader service. In this tutorial, we will learn how to enable and how to use it.

Database:
The Database for this tutorial is taken from the chinook database.
Source Code:
The source code of this project available in GitHub. It also contains the script of the database

Enabling Lazy Loading

Unlike the its predecessor EF Core does not support it out of the box. To Enable it you have two options

  1. Use the Microsoft.EntityFrameworkCore.Proxies Package
  2. Use the ILazyLoader Service

Proxies

The Lazy Loading in Entity Framework uses the Proxies classes. It was enabled by default as it was part of the man package. In EF Core the Proxies option is now part of the Microsoft.EntityFrameworkCore.Proxies package.

There three steps involved in enabling Lazy Loading using Proxies

  1. Install Proxies Package
  2. Enable Lazy Loading using UseLazyLoadingProxies
  3. Mark the Property as Virtual

Install Proxies

Install the Microsoft.EntityFrameworkCore.Proxies using the PMC Console as shown below. Ensure that you install the correct version as per your EF Core version. The latest version available is 3.1.3

Enable Lazy Loading

How to use the UseLazyLoadingProxies method depends on whether you are using .Net Core Console apps or ASP.NET Core

.NET Core Console Apps

In Console apps, you can enable it in the OnConfiguring method in the context class.

ASP.NET Core Apps

Open the startup.cs class in ASP.NET Core Apps and locate the ConfigureServices() method where you have AddDbContext method.

Mark the Property as Virtual

Finally, you need to add virtual keyword to any navigation property, which you want to participate in the Lazy Loading.

ILazyLoader Service

The second option is to inject the ILazyLoader service into an entity. ILazyLoader is part of the Microsoft.EntityFrameworkCore.Abstractions package. This package is already part of the main package and hence no need to install it separately.

Injecting ILazyLoader Service

There are two ways by which you can inject ILazyLoader service into a entity.

  1. Injecting the Lazyloader service (ILazyLoader).
  2. Using the Action<object, string> delegate to Inject the lazy-loading service

EF Core can inject few selected services into an entity type’s constructor. This does not depend on Dependency injection built into .NET Core / ASP.NET Core. It can inject only DbContext , ILazyLoader, a lazy-loading delegate Action<object, string> & IEntityType.

ILazyLoader Service

The following example shows how to inject ILazyLoader in the constructor of the entity. The constructor can be private

Note that you should also define a Parameter less constructor, otherwise you will not be able to create a new entity. i.e the statement (var album = new Album(); will throw an error.

lazy-loading delegate

The following example shows how to inject the ILazyLoader.Load method as a delegate.

Create a new PocoLoadingExtensions.cs class. Define the Load extension method as shown below. The load method loads related data.

Create Getter for Navigation Property

Once ILazyLoader  service using one of the methods above. You can create a separate getter & setter for each navigation property, where you want to implement Lazy Loading.

In the getter, use the _lazyLoader.Load(this, ref _Track); to load the entity, whenever the navigational property is accessed.

Lazy Loading in Action

Once you enabled it, You can try running this query.

Without Lazy Loading the loop foreach (var t in p.Track) will result in an error as EF core will not load the Tracks collection. But if it is working, the as soon as you tried to access the track the EF Core will sends a query to the database to get list of tracks

Similarly as soon as you access the p.Artist.Name it sends an another query to retentive the Artist entity.

Lazy Loading Pitfalls

Lazy Loading is a good feature to have. But it also creates lot of Performance issues, if you not carefull

For Example consider this query. It displays the Track name and album title of all the Tracks in the database and works perfectly correct.

The first query brings all the Track in the database at one go. But as you loop through the tracks it sends a query to the database to get the album title. It sends as many queries as there are Albums in the system. This is very inefficient and this kind of performance issue are easier to miss.

The EF Core will not load the same data again. In the above query, if an album is loaded once, it will not be queried again. Whether it is a good thing or a bad thing depends on the use case. For Example, in the above case, it is a good thing as it eliminates the duplication of the query. But if someone changes the data after you load the data, the EF will not refresh your data and you going to see only the old data.

Now, look at the following query. p.Album.Track.Count() A Simple operation of requesting a count will send a query to get the album & then a query to all the Tracks before returning the count.

Serialization

Serialization and Lazy loading do not work well. Especially when you have properties that hold a reference to each other. For example, consider the following model.

When you try to serialize the Trackinstance.

  1. The serializer starts to serialize the Track.
  2. It reads the Album property. The EF Core will send a query to the database get the Album
  3. Serializer attempt to serialize the Album.
  4. The Albumcontains the collection Tracks. The EF Core Lazy loads the Tracksfrom the database.
  5. Now Serializer attempts to read the each Trackin the Trackscollection.
  6. Each of those Trackhas Albumand the Albumhas Trackscollection
  7. The Loop goes on.

References

1 thought on “Lazy Loading in Entity Framework Core”

  1. I followed your example but it doesn’t work, I guess that’s because you failed to add something important. My constructor that gets passed the ILazyLoader parameter is never called, hence my _lazyLoader is always null. Why the heck is literally every EF Core 6 example (regardless of topic) I have looked into on the inet incomplete and doesn’t work?

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top