C# tutorials > Language Integrated Query (LINQ) > LINQ to Entities (Entity Framework Core) > Loading related data (eager loading, lazy loading, explicit loading)
Loading related data (eager loading, lazy loading, explicit loading)
Understanding Related Data Loading in Entity Framework Core
Entity Framework Core (EF Core) offers several strategies for loading related data, which are crucial for efficient data retrieval. These strategies include eager loading, lazy loading, and explicit loading. Each has its own benefits and drawbacks, affecting performance and application architecture. This tutorial explores these methods with practical C# examples.
Introduction to Related Data Loading
When working with relational databases, entities often have relationships with other entities (e.g., a Customer
entity might have a collection of Order
entities). Loading these related entities efficiently is essential. EF Core provides three primary ways to handle this:
Eager Loading
Eager loading is achieved using the Include
method. This instructs EF Core to load the related entities as part of the initial query. In this example, when retrieving Blogs
, the associated Posts
are also loaded in the same database query. This reduces the number of database round trips.
using Microsoft.EntityFrameworkCore;
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite("Data Source=blogging.db");
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; } // Navigation property
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; } // Navigation property
}
// Usage
using (var context = new BloggingContext())
{
var blogs = context.Blogs
.Include(b => b.Posts) // Eagerly load Posts
.ToList();
foreach (var blog in blogs)
{
Console.WriteLine($"Blog: {blog.Url}");
foreach (var post in blog.Posts)
{
Console.WriteLine($" Post: {post.Title}");
}
}
}
Lazy Loading
Lazy loading loads related entities automatically when they are accessed. To enable it, you typically need to install the Microsoft.EntityFrameworkCore.Proxies
package and configure it in OnConfiguring
by calling .UseLazyLoadingProxies()
. Navigation properties must be declared as virtual
. When you access blog.Posts
for the first time, EF Core will execute a separate query to load the posts for that blog.
using Microsoft.EntityFrameworkCore;
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options
.UseSqlite("Data Source=blogging.db")
.UseLazyLoadingProxies();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.UsePropertyAccessMode(PropertyAccessMode.Field);
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public virtual List<Post> Posts { get; set; } // Navigation property
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public virtual Blog Blog { get; set; } // Navigation property
}
// Usage
using (var context = new BloggingContext())
{
var blogs = context.Blogs.ToList();
foreach (var blog in blogs)
{
Console.WriteLine($"Blog: {blog.Url}");
foreach (var post in blog.Posts) // Posts are loaded when accessed here
{
Console.WriteLine($" Post: {post.Title}");
}
}
}
Explicit Loading
Explicit loading allows you to load related entities at any point in time using the Load
method on the Collection
or Reference
navigation property. In this example, we first retrieve a Blog
without its posts, and then explicitly load the posts using context.Entry(blog).Collection(b => b.Posts).Load()
.
using Microsoft.EntityFrameworkCore;
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite("Data Source=blogging.db");
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; } // Navigation property
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; } // Navigation property
}
// Usage
using (var context = new BloggingContext())
{
var blog = context.Blogs.FirstOrDefault();
// Load posts explicitly
context.Entry(blog).Collection(b => b.Posts).Load();
Console.WriteLine($"Blog: {blog.Url}");
foreach (var post in blog.Posts)
{
Console.WriteLine($" Post: {post.Title}");
}
}
Concepts Behind the Snippets
The core concept is about managing the relationship between entities in a database and how these relationships are materialized in your application's object model. Each loading strategy addresses the trade-off between initial query performance and the potential for additional database queries later on.
Real-Life Use Case Section
Eager Loading: Use when you know you'll need the related data in almost all cases, such as displaying a blog post with its comments. Avoid it when the related data is rarely used to prevent over-fetching. Lazy Loading: Good for scenarios where you only need related data occasionally. For example, displaying detailed order information with customer details which might not always be required in a simple order list. Be cautious to avoid N+1 problem. Explicit Loading: Useful when you need fine-grained control over when related data is loaded, typically in scenarios with conditional requirements. For example, loading user roles based on a specific condition or permission.
Best Practices
Select
to load only the data you need.
Interview Tip
Be prepared to explain the differences between eager, lazy, and explicit loading, and the pros and cons of each. Discuss the N+1 problem and how to avoid it. Mention performance considerations and the importance of choosing the right loading strategy for a given scenario.
When to use them
Eager Loading: When you almost always need the related data and want to minimize database round trips. Lazy Loading: When you only need the related data occasionally and want to avoid loading unnecessary data upfront. Explicit Loading: When you need fine-grained control over when related data is loaded, typically based on certain conditions or user interactions.
Memory footprint
Eager Loading: Can result in a larger memory footprint because all related data is loaded upfront. Lazy Loading: Has a smaller initial memory footprint, but the overall memory footprint can increase as related data is accessed. Explicit Loading: Offers the most control over memory usage, as you only load related data when needed.
Alternatives
Projections: Use Stored Procedures: Use stored procedures for complex data retrieval scenarios. They can optimize database performance and reduce the amount of data transferred over the network.Select
to project data into a DTO (Data Transfer Object), loading only the necessary fields. This can significantly improve performance, especially for read-only scenarios.
Pros and Cons
Eager Loading: Lazy Loading: Explicit Loading:
FAQ
-
What is the N+1 problem?
The N+1 problem occurs when retrieving a collection of entities and then retrieving related entities for each item in the collection, resulting in N+1 database queries (one for the initial entities and one for each related entity). -
How can I prevent the N+1 problem?
You can prevent the N+1 problem by using eager loading (Include
) or by using a single query to retrieve all necessary data with projections. -
When should I use eager loading?
Use eager loading when you almost always need the related data and want to minimize database round trips. -
When should I use lazy loading?
Use lazy loading when you only need the related data occasionally and want to avoid loading unnecessary data upfront. Be mindful of the N+1 problem. -
When should I use explicit loading?
Use explicit loading when you need fine-grained control over when related data is loaded, typically based on certain conditions or user interactions.