EF Core - Lazy Loading


What Is Lazy Loading in EF Core?

Lazy loading is a data retrieval strategy in EF Core where related entities are loaded automatically when they are accessed for the first time. This technique can help optimize performance by deferring the loading of related data until it is actually needed, reducing the initial load time.


Types of Loading Strategies in EF Core

EF Core provides several strategies for loading related data. The following table summarizes the main types:

Strategy Description Use Case
Eager Loading Loads related entities as part of the initial query. When you need related data immediately.
Lazy Loading Loads related entities on demand when accessed. When related data is not always needed.
Explicit Loading Loads related entities manually by calling methods. When you need precise control over data loading.

1. Introduction to Lazy Loading

Lazy loading in EF Core allows you to defer the loading of related entities until they are accessed, which can improve performance by reducing the initial query size. This strategy is useful when related data is not always needed immediately.

        
            
public class Order
{
    public int OrderId { get; set; }
    public DateTime OrderDate { get; set; }
    public virtual Customer Customer { get; set; }
    public virtual ICollection<OrderItem> OrderItems { get; set; }
}

public class Customer
{
    public int CustomerId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Order> Orders { get; set; }
}
        
    

This example introduces the concept of lazy loading and its importance in optimizing data retrieval in EF Core.


2. Enabling Lazy Loading

Lazy loading can be enabled in EF Core by installing the Microsoft.EntityFrameworkCore.Proxies package and configuring the DbContext to use lazy loading proxies.

        
            
public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseLazyLoadingProxies();
    }
}
        
    

This example demonstrates how to enable lazy loading in EF Core using lazy loading proxies.


3. Using Virtual Navigation Properties

To enable lazy loading, navigation properties must be declared as virtual so that EF Core can override them to add lazy loading behavior.

        
            
public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }
    public virtual Category Category { get; set; }
}
        
    

This example shows how to declare virtual navigation properties for lazy loading in EF Core.


4. Lazy Loading with Collections

Lazy loading can be used to automatically load collections of related entities, such as a list of orders for a customer, when they are accessed.

        
            
var customer = _context.Customers.Find(1);
var orders = customer.Orders; // Orders are loaded automatically when accessed.
        
    

This example illustrates how to use lazy loading with collections in EF Core.


5. Lazy Loading with Reference Properties

Lazy loading can also be used with reference properties, such as loading a customer's address when the address property is accessed.

        
            
var order = _context.Orders.Find(1);
var customer = order.Customer; // Customer is loaded automatically when accessed.
        
    

This example demonstrates how to use lazy loading with reference properties in EF Core.


6. Handling Circular References with Lazy Loading

Circular references can occur when entities reference each other in a loop. Lazy loading can handle circular references, but care must be taken to avoid infinite loops.

        
            
public class Employee
{
    public int EmployeeId { get; set; }
    public string Name { get; set; }
    public int? ManagerId { get; set; }
    public virtual Employee Manager { get; set; }
    public virtual ICollection<Employee> Subordinates { get; set; }
}
        
    

This example shows how to handle circular references with lazy loading in EF Core.


7. Performance Considerations with Lazy Loading

While lazy loading can improve performance by deferring data retrieval, it can also lead to the N+1 query problem. Understanding when and how to use lazy loading is key to optimizing performance.

        
            
var orders = _context.Orders.ToList();
foreach (var order in orders)
{
    var customer = order.Customer; // Lazy loading can lead to N+1 queries here.
}
        
    

This example provides tips for optimizing performance when using lazy loading in EF Core.


8. Lazy Loading vs. Eager Loading

Comparing lazy loading and eager loading helps you understand the trade-offs between these strategies and choose the right approach for your application.

        
            
var lazyLoadedOrders = _context.Orders.ToList();
foreach (var order in lazyLoadedOrders)
{
    var items = order.OrderItems; // Loaded on demand.
}

var eagerLoadedOrders = _context.Orders
    .Include(o => o.OrderItems)
    .ToList(); // Loaded with the initial query.
        
    

This example compares lazy loading with eager loading and discusses when to use each strategy in EF Core.


9. Testing Lazy Loading

Testing lazy loading involves verifying that related data is correctly loaded when accessed and that performance is optimized. This section covers testing strategies for lazy loading.

        
            
var order = _context.Orders.Find(1);
Assert.NotNull(order.Customer); // Lazy loading loads Customer when accessed.
        
    

This example demonstrates techniques for testing lazy loading in EF Core.


10. Configuring Lazy Loading in EF Core 8

EF Core 8 provides enhancements for configuring and using lazy loading, offering more options and flexibility for developers.

        
            
public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Order>().Navigation(o => o.Customer).UseLazyLoading();
    }
}
        
    

This example highlights the enhancements for lazy loading in EF Core 8.


11. Advanced Techniques for Lazy Loading

Advanced techniques for lazy loading involve customizing the loading behavior and combining lazy loading with other strategies to optimize data retrieval.

        
            
var orders = _context.Orders.ToList();
foreach (var order in orders)
{
    var items = order.OrderItems; // Lazy loading.
    if (items.Count > 5)
    {
        // Perform some operation
    }
}
        
    

This example explores advanced techniques for using lazy loading in EF Core.


12. Best Practices for Lazy Loading

Following best practices when using lazy loading can help ensure efficient and maintainable code. Consider the following guidelines:


Summary

Lazy loading in EF Core provides a flexible and efficient way to load related data on demand, helping to reduce initial load times and improve perceived performance. By understanding how to enable and use lazy loading effectively, developers can optimize their applications for better data retrieval and performance. Combining lazy loading with other strategies like eager loading and explicit loading allows for a balanced approach to data access.