Lazy Loading in Entity Framework Core

Lazy loading means loading data on demand, we have lazy class in c# programming, that allow us to perform lazy loading child entities, here in this tutorial we will learn how to lazy load related entities using entity framework.

Lazy loading helps in performance improvement, in this example we use console application with entity framework to perform database operations.

Business requirement and database tables

We create few business entities like Client, Order, OrderItem, Product and SQL view to replicate exact business scenario where we can load client information along with order item details, a client can have a long list of order items, and we apply lazy loading to load the order item details

Entity Framework Core Lazy Loading

First, we create database objects (tables and view), here I will share all scripts, so you can quickly replicate the development environment in your local machine.

Create client table called "tbClient"

    CREATE TABLE [dbo].[tbClient](
	[clientId] [bigint] IDENTITY(1,1) NOT NULL,
	[Firstname] [varchar](50) NOT NULL,
	[Lastname] [varchar](50) NULL,
	[Email] [varchar](50) NULL,
	[Mobile] [varchar](50) NULL,
	[Address] [varchar](50) NULL,
PRIMARY KEY CLUSTERED 
(
	[clientId] ASC
)WITH (PAD_INDEX = OFF) ON [PRIMARY]
) ON [PRIMARY]

Cerate order table called “tbOrder” for capturing order details, each order can have multiple order items

CREATE TABLE [dbo].[tbOrder](
	[orderId] [bigint] IDENTITY(1,1) NOT NULL,
	[orderDate] [datetime] NOT NULL,
	[clientId] [bigint] NOT NULL,
	[description] [varchar](500) NULL,
	[deliverynote] [varchar](500) NULL,
	[isClosed] [bit] NULL,
PRIMARY KEY CLUSTERED 
(
	[orderId] ASC
)WITH (PAD_INDEX = OFF) ON [PRIMARY]
) ON [PRIMARY]

One order can have multiple items, so this table willl have those records (note this data will try to load on demand [known as lazy loading] in our application)

CREATE TABLE [dbo].[tbOrderItem](
	[oitemId] [bigint] IDENTITY(1,1) NOT NULL,
	[orderId] [bigint] NOT NULL,
	[productId] [bigint] NOT NULL,
	[quantity] [int] NOT NULL,
	[unitPrice] [decimal](18, 2) NOT NULL,
	[totalPrice] [decimal](18, 2) NOT NULL,
PRIMARY KEY CLUSTERED 
(
	[oitemId] ASC
)WITH (PAD_INDEX = OFF) ON [PRIMARY]
) ON [PRIMARY]

Now we create product table, in my application I had something called TbStock , you can rename to tbProduct

    CREATE TABLE [dbo].[tbStock](
	[StockId] [bigint] IDENTITY(1,1) NOT NULL,
	[quantity] [int] NOT NULL,
	[price] [decimal](18, 2) NOT NULL,
	[productName] [varchar](50) NOT NULL,
	[updatedOn] [datetime] NOT NULL,
PRIMARY KEY CLUSTERED 
(
	[StockId] ASC
)WITH (PAD_INDEX = OFF) ON [PRIMARY]
) ON [PRIMARY]
Creating business entities

now we have your database object structure ready, so we have to create similar structure in our c# code, note we can have different property name and object name, but in this example I will keep everything almost same, so it will be easy to understand for everyone.

[Table("tbClient")]
public class Client
{
    [Key]
    public long ClientId { get; set; }
    public string Firstname { get; set; } = "Not Set";
    public string Lastname { get; set; } = "Not Set";
    public string Address { get; set; }
    public string Mobile { get; set; }
    public string Email { get; set; }
    [NotMapped]
    public Lazy<List<OrderItem>> OrderItems { get; set; }
    [NotMapped]
    public Lazy<List<vwClientOrder>> OrderList { get; set; }
}

Here we see how to load all entity related child objects, in entity framework core there are the three different type of loadings supported; eager loading, explicit loading and lazy loading, now to define lazy loading as per entity framework core we need to use ILazyLoader instance, which comes under Microsoft.EntityFrameworkCore.Infrastructure, then load the collection into a ICollection<OrderItem> Orderlists property of that object.

However, here we see different way of implementing lazy collection into a lazy property list!

Accessing data using DbContext

Asynchronously we load child objects into lazy property from dbContext object.

EF Core Lazy Loading

Write following code in DbContext file model creating method, you need to override the OnModelCreating method.

protected override void OnModelCreating(ModelBuilder modelBuilder)
    {           
        modelBuilder.Entity<Client>().HasKey(s => s.ClientId);
        modelBuilder.Entity<Order>().HasKey(s => s.OrderId);
        modelBuilder.Entity<OrderItem>(ov =>
        {
            ov.HasKey(v => v.OrderItemId);
            ov.ToTable("tbOrderItem");
            ov.Property(v => v.OrderItemId).HasColumnName("oItemId");
        });
        modelBuilder.Entity<Stock>().HasKey(s => s.StockId);
        modelBuilder
            .Entity<vwClientOrder>(ov =>
            {
                ov.HasNoKey();
                ov.ToView("vwOrderItem");
                ov.Property(v => v.clientId).HasColumnName("clientId");
            });
        base.OnModelCreating(modelBuilder);
    }

Now using DbContext class load the client details and the lazy order list property, note here i have used await because the main method was async, even if you want to create non-async method then also the syntax will remain same, only you need to remove the await keyword and instead of FirstOrDefaultAsync call FirstOrDefault

using (var context = new EFContext())
{
client = await context.tbClient
		.Where(c => c.ClientId == clientId)
		.FirstOrDefaultAsync<Client>();
	List<vwClientOrder> orderItems = await context.vwOrderItem
			 .Where(o => o.clientId == clientId)
			 .ToListAsync<vwClientOrder>();
	client.OrderList = new Lazy<List<vwClientOrder>>(orderItems);

You may be interested in following posts!

 
EF Core Lazy Loading
Learn entity framework orm using c#, entity framework core and earlier version of entity framework, all tutorials are written in c#.
Entity Framework Interview Questions

SQL interview questions
Entity Framework C# Examples | Join .Net C# Course