In Entity Framework, we can control how we want to load related data with an entity.
In a relational database, entities are related to each other through primary and foreign keys.
Loading related data refers to how and when the data of related entities is retrieved in a query.
For example, in an online store database, we might have an entity Order
that is related to an entity Customer
.
When we retrieve an Order
, we may also want to obtain the data of the associated Customer
.
It is very common that we want to get this related data (in fact, we will do it continuously).
However, the way we do it can have a significant impact on the speed and performance of our application ⚡.
Strategies for Loading Related Data
Entity Framework allows us to load related entities in three different ways:
- Eager Loading: Loads all related entities at once, in the same query.
- Lazy Loading: Loads related entities only when they are accessed.
- Explicit Loading: Loads related entities manually, when the developer decides.
As expected, each has its advantages and disadvantages, and a suitable scenario where it is appropriate to use one or the other.
Let’s look at each of the strategies in detail.
Eager Loading
Eager Loading is a strategy in which all related entities are loaded at once, along with the main entity. This is achieved using the Include
method in our LINQ queries.
Suppose we have the following entities:
public class Customer
{
public int CustomerId { get; set; }
public string Name { get; set; }
public ICollection<Order> Orders { get; set; }
}
public class Order
{
public int OrderId { get; set; }
public DateTime Date { get; set; }
public int CustomerId { get; set; }
public Customer Customer { get; set; }
}
If we want to retrieve a Customer
along with all its Orders
, we can use Eager Loading as follows:
using (var context = new MyContext())
{
var customer = context.Customers
.Include(c => c.Orders)
.FirstOrDefault(c => c.CustomerId == 1);
}
In this example, Entity Framework will generate a SQL query that retrieves both the Customer
and its related Orders
in a single query.
Lazy Loading
Lazy Loading is a strategy in which related entities are loaded only when they are accessed for the first time. This means that initially, only the main entity is loaded, and the related entities are loaded on demand.
To enable Lazy Loading in Entity Framework, we must ensure that our navigation properties are marked as virtual
:
public class Customer
{
public int CustomerId { get; set; }
public string Name { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
Then, we can retrieve a Customer
without loading its Orders
immediately:
using (var context = new MyContext())
{
var customer = context.Customers
.FirstOrDefault(c => c.CustomerId == 1);
// The Orders will be loaded only when accessed
var orders = customer.Orders;
}
In this case, Entity Framework will generate a SQL query to retrieve the Customer
, and then, when we access customer.Orders
, it will generate another query to retrieve the related Orders
.
Explicit Loading
Explicit Loading is a strategy in which the developer decides when to load related entities. This is done manually using the Load
method on the DbContext
.
Suppose we want to load the Orders
of a Customer
only when we decide to:
using (var context = new MyContext())
{
var customer = context.Customers
.FirstOrDefault(c => c.CustomerId == 1);
// Explicitly load the Orders
context.Entry(customer)
.Collection(c => c.Orders)
.Load();
}
In this example, Entity Framework will generate a SQL query to retrieve the Customer
, and then, when we call Load
, it will generate another query to retrieve the related Orders
.
When to Use Each Strategy?
The most important question is when to use each of these strategies. Let’s start by looking at a summary of each strategy.
Characteristic | Eager Loading | Lazy Loading | Explicit Loading |
---|---|---|---|
Data Loading | All related data is loaded at once | Related data is loaded on demand | Related data is manually loaded |
Number of Queries | A single query | Multiple queries (N+1) | Multiple queries (under control) |
Performance | Better when all data is needed | Better when few related data is accessed | Better when total control is needed |
Code Complexity | Simple | Simple | More complex |
Now, let’s see when it is convenient to use each of them, along with their advantages and disadvantages.
Eager Loading
Useful when we know that we will need all related data from the start.
For example, on a details screen where all data of an entity and its relationships are displayed.
- Reduction of database queries: By loading all related entities at once, the number of queries to the database is minimized.
- Better performance in certain scenarios: If we know we will need the related data, Eager Loading can be more efficient than making multiple queries.
- Data Overhead: If we load more data than necessary, we may end up with excess information in memory, which can affect performance.
Lazy Loading
Useful when we are not sure whether we will need the related data, or when we will only access them under certain conditions.
For example, in a list of entities where details are only loaded when clicking on an item.
- On-demand loading: Data is only loaded when truly needed, which can save memory and execution time.
- Simplicity in code: There’s no need to specify which related entities to load, simplifying the code.
- Performance Issues: If we access many related entities, we can end up with a large number of queries to the database, known as the “N+1 queries” problem.
Explicit Loading
Useful when we need total control over when and what related data to load.
For example, in a complex application where performance is critical and we want to avoid unnecessary loads.
- Total Control: The developer has total control over when and which related entities to load.
- Avoids the N+1 query problem: By manually loading related entities, we can avoid the N+1 query problem that occurs with Lazy Loading.
- More Complex Code: The code can become more verbose and complex, as we have to manually handle the loading of related entities.
- Higher Risk of Errors: By having to manually handle the loading of entities, there is a higher risk of errors and oversights.
Best Practices
Although Eager Loading can be efficient, overusing it or using it with very large relationships can result in overly complex queries and excessive data loading.
Conversely, with Lazy Loading you might encounter an N+1 query problem (it occurs when EF Core performs an additional query for each loaded entity). Make sure to avoid implicitly loading unnecessary relationships.