C# tutorials > Frameworks and Libraries > Entity Framework Core (EF Core) > Eager loading, lazy loading, and explicit loading
Eager loading, lazy loading, and explicit loading
This tutorial explains the concepts of eager loading, lazy loading, and explicit loading in Entity Framework Core (EF Core) with C#. Understanding these concepts is crucial for optimizing database queries and application performance. Choosing the right loading strategy depends on your specific application requirements and data access patterns.
Introduction to Loading Strategies in EF Core
Entity Framework Core offers three primary strategies for loading related data: eager loading, lazy loading, and explicit loading. Each approach has its advantages and disadvantages concerning performance, memory usage, and code complexity. Understanding these differences allows developers to make informed decisions about which strategy is best suited for their application's specific needs.
Eager Loading
Eager loading involves loading related entities along with the primary entity in a single query. This is achieved using the Include
method. In the example, context.Blogs.Include(b => b.Posts)
loads all blogs and their associated posts in one database trip. This can improve performance when you know you'll need the related data.
Explanation of the code:
BloggingContext
inheriting from DbContext
. This represents our database context.Blog
and Post
entities, with a one-to-many relationship (a Blog can have many Posts).Include(b => b.Posts)
method on the Blogs
DbSet instructs EF Core to retrieve the associated Posts for each Blog in the same SQL query.
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; }
}
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; }
}
// Eager loading example:
using (var context = new BloggingContext())
{
var blogs = context.Blogs.Include(b => b.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 postpones the loading of related entities until they are explicitly accessed. This is typically implemented using proxy objects. When you access a navigation property (like blog.Posts
), EF Core automatically executes a separate query to load the related data. Lazy loading requires the Microsoft.EntityFrameworkCore.Proxies
package and configuration in the OnConfiguring
method.
Explanation of the code:
Important note: Lazy loading can lead to the N+1 problem, where accessing related entities for N primary entities results in N+1 database queries (1 query for the primary entities and N queries for the related entities). This can significantly impact performance.Microsoft.EntityFrameworkCore.Proxies
NuGet package.OnConfiguring
method of your DbContext
, you must configure lazy loading by calling options.UseLazyLoadingProxies()
.Posts
property of a Blog
object, EF Core will automatically execute a separate query to retrieve the related posts from the database.
// Requires installation of the Microsoft.EntityFrameworkCore.Proxies package
// and configuration in OnConfiguring:
// options.UseLazyLoadingProxies().UseSqlite("Data Source=blogging.db");
// Example with lazy loading enabled:
using (var context = new BloggingContext())
{
var blog = context.Blogs.FirstOrDefault(); // Loads only the Blog entity
if (blog != null)
{
Console.WriteLine($"Blog: {blog.Url}");
// The Posts are loaded only when accessed (Lazy Loading)
foreach (var post in blog.Posts)
{
Console.WriteLine($" Post: {post.Title}");
}
}
}
Explicit Loading
Explicit loading provides the most control over when related data is loaded. You load the primary entity first and then explicitly load the related entities using the Load
method. This approach is useful when you only need related data in specific situations. It avoids the performance issues associated with the N+1 problem if lazy loading is used inappropriately.
Explanation of the code:
Blog
entity from the database.context.Entry(blog).Collection(b => b.Posts).Load()
explicitly loads the Posts
collection associated with the blog
.
using (var context = new BloggingContext())
{
var blog = context.Blogs.FirstOrDefault(); // Loads only the Blog entity
if (blog != null)
{
Console.WriteLine($"Blog: {blog.Url}");
// Explicitly load the Posts for the blog
context.Entry(blog).Collection(b => b.Posts).Load();
foreach (var post in blog.Posts)
{
Console.WriteLine($" Post: {post.Title}");
}
}
}
Concepts Behind the Snippets
Object Relational Mapping (ORM): EF Core is an ORM, which means it maps objects in your code to tables in your database. This allows you to work with data in a more object-oriented way, without having to write SQL queries directly. Navigation Properties: Navigation properties (like DbContext: The Blog.Posts
) represent the relationships between entities. They allow you to navigate from one entity to related entities.DbContext
class represents a session with the database. It provides methods for querying, saving, and deleting data.
Real-Life Use Case Section
Eager Loading: Use eager loading when you know you will always need the related data. For example, when displaying a blog post with its comments, you might eagerly load both the post and its comments in a single query. Lazy Loading: Use lazy loading when you only need the related data in specific scenarios. For instance, if you have a user profile page and only need to display the user's address sometimes, you can lazy load the address. Explicit Loading: Use explicit loading when you need precise control over when related data is loaded. For example, in a data processing pipeline, you might load related data only when certain conditions are met.
Best Practices
ToListAsync
instead of ToList
) to avoid blocking the UI thread.
Interview Tip
Be prepared to explain the differences between eager loading, lazy loading, and explicit loading. Discuss the pros and cons of each approach and provide examples of when you would use each one. Also, understand the N+1 problem and how to mitigate it.
When to Use Them
Memory Footprint
Eager loading generally has a higher memory footprint than lazy or explicit loading because it loads all related data at once. Lazy loading has a lower initial memory footprint, but it can increase as related data is accessed. Explicit loading offers the most control over memory usage.
Alternatives
As an alternative to these loading strategies, consider using projection. By selecting only the properties you need, you can reduce the amount of data transferred from the database and improve performance. For example:
var blogTitles = context.Blogs.Select(b => b.Url).ToList();
This code only retrieves the `Url` property of the `Blog` entities, avoiding loading the entire entity and any related entities.
Pros and Cons
Eager Loading: Lazy Loading: Explicit Loading:
FAQ
-
What is the N+1 problem?
The N+1 problem occurs when lazy loading is used improperly. It results in one initial query to retrieve the primary entity and N additional queries to retrieve related entities, where N is the number of primary entities. This can significantly impact performance. -
How can I prevent the N+1 problem?
You can prevent the N+1 problem by using eager loading, explicit loading, or projection. Eager loading retrieves all related data in a single query. Explicit loading allows you to load related data on demand. Projection allows you to select only the data you need, avoiding loading entire entities. -
When should I use eager loading?
Use eager loading when you know you will 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 in some cases and want to avoid loading unnecessary data. Be careful to monitor your query performance to avoid 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 and want to avoid the N+1 problem.