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.
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
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]
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!
Asynchronously we load child objects into lazy property from dbContext object.
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!