In Entity Framework, we can control how we want to load related data for 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 Order entity that is related to a Customer entity.
When we retrieve an Order, we might also want to get the data of the associated Customer.
It is very common that we want to retrieve this related data (in fact, we will do it constantly).
However, the way we do it can have a great 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 could not be otherwise, each one has its advantages and disadvantages, and a suitable scenario where it is convenient to use one or the other.
Let’s look at each of the strategies in detail.
Eager Loading
Eager Loading is a strategy where all related entities are loaded at once, along with the main entity. This is achieved by 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 where related entities are loaded only when they are accessed for the first time. This means that initially, only the main entity is loaded, and 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 where 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:
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 seeing 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 loaded manually |
| Number of Queries | Single query | Multiple queries (N+1) | Multiple queries (under control) |
| Performance | Better when all data is needed | Better when accessing few related data | Better when total control is needed |
| Code Complexity | Simple | Simple | More complex |
Now, let’s see when it is convenient to use each one, with its advantages and disadvantages.
Eager Loading
Useful when we know we will need all related data from the beginning.
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 database queries 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 can end up with an excess of information in memory, which can affect performance.
Lazy Loading
Useful when we are not sure if 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 it is really needed, which can save memory and execution time.
- Code simplicity: It is not necessary to specify which related entities to load, which simplifies the code.
- Performance issues: If we access many related entities, we can end up with a large number of database queries, 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 what related entities to load.
- Avoids the N+1 queries problem: By loading related entities manually, we can avoid the N+1 queries problem that occurs with Lazy Loading.
- More complex code: The code can become more verbose and complex, as we must manually handle the loading of related entities.
- Higher risk of errors: Having to manually handle entity loading carries a higher risk of errors and omissions.
Best Practices
Although Eager Loading can be efficient, using it excessively or with very large relationships can result in overly large queries and downloading too much data.
On the other hand, with Lazy Loading you can have an N+1 queries problem (it occurs when EF Core performs an additional query for each loaded entity). Make sure not to load unnecessary relationships implicitly.
