Working With Lazy Loading and Eager Loading in Entity Framework Core and Entity Developer
This article presents a discussion on how we can work with lazy loading using EF Core and Entity Developer for data access.
Join the DZone community and get the full member experience.
Join For FreeEntity Framework is an Object Relational Mapper (ORM) tool from Microsoft that has been an extremely popular from the time it was available. It enables developers to create data-centric applications by programming against a conceptual model rather than the relational model thereby solving the impedance mismatch between the way data is represented in the application and how it is actually stored in the database. While Entity Framework runs on .NET Framework, Entity Framework Core can run on .NET Core environment.
While Entity Framework runs on .NET Framework, Entity Framework Core can run on .NET Core environment.
This article presents a discussion on how we can work with lazy loading using EF Core and Entity Developer for data access.
Prerequisites
To be able to work with the code examples demonstrated in this article, you should have the following installed in your system:
- Visual Studio 2019 Community Edition or higher
- SQL Server 2019 Developer Edition or higher
- Entity Developer from Devart
You can download Visual Studio 2019 from here.
You can download SQL Server 2019 Developer Edition from here.
You can download a copy of Entity Developer (trial version) from here.
Entity Developer: A Visual ORM Designer Tool
We’ll take advantage of Entity Developer to generate the model and corresponding classes. Entity Developer from Devart is a modeling and code generation tool that lets you design your data access layer visually and helps you to become more productive as a developer. You can take advantage of Entity Developer to generate data access layer code automatically using one unified interface – as a result, chances of error creeping into your Data Access code are minimal.
Entity Developer is integrated nicely with Visual Studio upon installation and supports ADO.NET Entity Framework, Entity Framework Core, Hibernate, LinqConnect, Telerik Data Access, and LINQ to SQL. You can get started using Entity Developer after downloading a trial version from here.
Creating the Database
First off, we need to have a database against which the queries will be executed. For the sake of simplicity, we’ll take advantage of the Northwind database rather than creating our own database. If you don’t have the Northwind database available, you can get the script(s) from here.
Create a New ASP.NET Core Project
Assuming that the necessary software has been installed in your computer to be able to work with Entity Developer, follow the steps outlined below to create a new ASP.NET Core Web API project.
- First off, open the Visual Studio 2019 IDE
- Next, click "Create a new project" once the IDE has loaded
- Click "Create a new project"
- Next, select "ASP.NET Core Web Application"
- Click the "Next" button
- Specify the project name and location — where it should be stored in your system
- Optionally, click the "Place solution and project in the same directory" checkbox.
- Next, click the "Create" button
- In the "Create a new ASP.NET Core Web Application" dialog window that is shown next, select "API" as the project template.
- Select ASP.NET Core 3.1 or later as the version.
- You should disable the "Configure for HTTPS" and "Enable Docker Support" options by disabling the respective checkboxes.
- Since we'll not be using authentication in this example, specify authentication as "No Authentication".
- Finally, click on the "Create" button to finish the process.
Create an Entity Data Model
In this section, we’ll explore how to create an Entity Data Model using Entity Developer. We’ll use both the two approaches database first and model first. To create an Entity Data Model using Entity Developer in Visual Studio 2019, follow the steps outlined below.
- Right-click on the project in the Solution Explorer Window
- Select Add -> New Item as shown in Figure 1
Figure 1
- In the "Entity Developer: Create Model Wizard" window you can specify how the model should be created. You’ll have two choices – Database First and Model First
- Select the Database First Approach and click on Next to continue.
- In the next screen, specify the connection properties and click on the “Next” button to continue.
- Specify how the model should be generated in the next screen. Note that the “Generate from Database" option is selected by default.
- Since we’ll need the model to be created from the database, click on the “Next” button to continue.
- In the next screen the database metadata is retrieved by the Entity Developer runtime. Here’s where you should specify the database objects that should be a part of your Entity Data Model. Select the tables here as shown in Figure 2.
Figure 2
- In the "Set up naming rules" screen you can specify naming rules for your entities.
- Click on the "Next" button to continue.
- In the next screen, specify the Context Namespace as and click on the “Next” button to continue.
- Now you can specify what your model diagram should contain.
- Click on the "Next" button to continue.
- Now you can choose the code generation templates if you want to.
- Click on the "Next" button to continue.
Figure 3
- Click on the “Next” button again to continue.
- Click “Finish” to complete the process.
Your Entity Data Model using Entity Developer has been created. Here’s how your Entity Data Model would look like.
Figure 4
Eager Loading, Explicit Loading, and Lazy Loading
You can load similar entities using navigation properties in EF Core. Eager loading facilitates the loading of related entities as part of the original query. In EF Core, you may load similar entities at multiple levels by combining the Include() and ThenInclude() extension methods. You can load related entities in Entity Framework Core in one of the following ways:
- Eager Loading - This is used to load related entities as part of the initial query. The related data is loaded at the time when the query is executed using the Include() method.
- Explicit Loading - In Explicit Loading, when a query returns data, the related entities are not returned at the same time. They are only loaded when explicitly requested by the application using the Load method on the navigation property.
- Lazy Loading - This is used to load related entities when the navigation property is accessed. This is the default phenomenon used for delayed loading of related entities.
Working With Eager Loading
The following code snippet illustrates how you can use eager loading now.
var result = (from o in dataContext.Orders.Include("OrderDetails") select o);
You can also use LINQ method syntax to implement eager loading as well. The following code snippet shows how you can load related entities using Eager Loading in Entity Framework Core.
[HttpGet]
public IEnumerable<Order> Get()
{
using (NorthwindModel dataContext = new NorthwindModel())
{
var result = (from o in dataContext.Orders.Include("OrderDetails")
where o.ShipCity == "London" && o.OrderDetails.Select
(x => x.Discount == 0).FirstOrDefault()
select o);
return result;
}
}
Loading Multiple Levels of Related Entities
You can take advantage of the ThenInclude() method to load multiple levels of related entities as well. Here's an example:
var data = dataContext.Orders.Include(orders => orders.OrderDetails).ThenInclude(orders => orders.Product).ToList();
Here's another example - this one uses the AdventureWorks database.
using (var context = new AdventureWorksContext())
{
var data = context.Employee
.Include(j => j.JobCandidate)
.ThenInclude(b => b.BusinessEntity)
.ToList();
}
It is also possible to chain multiple calls to the ThenInclude() extension method to load data in multiple levels. The following code snippet shows how multiple calls to the ThenInclude() extension method can be chained.
var data = context.Customer
.Include(d => d.SalesOrderHeader)
.ThenInclude(p => p.SalesOrderDetail)
.ThenInclude(t => t.SalesOrder)
.ToList();
Working With Lazy Loading
Lazy loading is a pattern that enables you to defer the loading of data till the time it is actually needed. While this might give you benefits in certain use cases, it can also degrade the application's performance in certain other use cases such as web applications. It should be noted that Entity Framework Core does not support Lazy Loading out of the box - you need to enable it explicitly. Lazy loading can be enabled using one of the following ways:
- Using Proxies
- Using the ILazyLoader service
Using Proxies
Install the Microsoft.EntityFrameworkCore.Proxies package onto your project using the NuGet Package Manager. Next, you can take advantage of the UseLazyLoadingProxies method to facilitate the creation of proxies in the OnConfiguring method of your DbContext as shown in the following code snippet:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
//Other code
optionsBuilder.UseLazyLoadingProxies();
CustomizeConfiguration(ref optionsBuilder);
base.OnConfiguring(optionsBuilder);
}
Lastly, you should ensure that the navigation properties are marked as virtual. That's all you need to do!
Using the ILazyLoader Interface
You can leverage the ILazyLoader interface to lazy load the navigation properties. To be able to use this approach, you should install the Microsoft.EntityFrameworkCore.Abstractions package onto your project. Next, you should reference the Microsoft.EntityFrameworkCore.Infrastructure assembly in your program to be able to use the ILazyLoader interface.
Your entity class should have two constructors - one that accepts a reference to the ILazyLoader interface as a parameter and the other is a default constructor. The following code snippet illustrates how lazy loading can be implemented using the ILazyLoader interface.
using Microsoft.EntityFrameworkCore.Infrastructure;
public class Order
{
private readonly ILazyLoader _lazyLoader;
public Order()
{
}
public Order(ILazyLoader lazyLoader)
{
_lazyLoader = lazyLoader;
}
private List<Customer> _customers;
public int OrderID { get; set; }
public List<Customer> Customers
{
get => _lazyLoader.Load(this, ref _customers);
set => _customers = value;
}
}
Disabling Lazy Loading
You can turn off lazy loading at the db context level by setting the LazyLoadingEnabled property to false as shown in the code snippet below:
ChangeTracker.LazyLoadingEnabled = false;
Here's the updated version of the NorthwindModelOptimized class with the above change incorporated.
public sealed class NorthwindModelOptimized: NorthwindModel
{
public NorthwindModelOptimized()
{
ChangeTracker.QueryTrackingBehavior =
QueryTrackingBehavior.NoTracking;
this.ChangeTracker.LazyLoadingEnabled = false;
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Write your implementation here
}
}
Summary
Entity Framework Core, a lightweight cross-platform version of Entity Framework, provides you a standard way to access data from several data sources. It includes support for both Eager Loading as well as Lazy Loading. Albeit the benefits, both have their downsides as well. For example, you can disable lazy loading if you wouldn’t want to use it.
Opinions expressed by DZone contributors are their own.
Comments