Skip to content

Implementing Lazy Loading with Entity Framework Core

Implementing Lazy Loading with Entity Framework Core

In this article, we’ll be implementing-lazy loading with Entity Framework Core. Lazy loading is an Entity Framework’s feature that allows entities to be loaded on-demand rather than all at once when querying the database. This means related data is not retrieved from the database until explicitly accessed.

To clarify what I mean by that, Imagine an e-commerce app with two related entities. Customers and Orders. A Customerobject contains a collection of Orders. You can find the source code for this article in this GitHub repository. This is a customer object:

Let’s add it to the database.

Next, I’ll load the customer from the database and log the number of its orders.

And this is the output:

But the customer we inserted into the database had an order. And the order was inserted into the database when we added the customer. The thing is, it’s saved but not loaded.

One way to load the customer’s orders we can use the Include()method as follows.

Now the Customer‘s number of orders is 1. Look at the output:

 

EF doesn’t load the related data (like the Orders in our example) by default for performance reasons. On the one hand, not every time we load a customer, we need all its related orders, and on the other hand, loading large graphs of data in memory is not optimal. We need to explicitly Include the related data we need.

Loading Related Data Lazily

Sometimes you don’t want to call Include everywhere. That’s where lazy loading can help us. The easiest way to enable lazy-loading in EF is to install the Microsoft.EntityFrameworkCore.Proxies package and use the UseLazyLoadingProxies() option:

 

Now, let’s load the customer without explicitly including the orders again and log its orders.

This time the output is:

And we didn’t call the Include() method this time, but the related data (customer’s orders) are loaded.

Does it load the entire graph of related objects? The answer is no; it doesn’t. The following line doesn’t load the Orders.

But the following line does:

Customers’ orders aren’t loaded as long as they’re not needed. However, calling  Customer.Orders.Count goes to the database behind the scenes and loads up the customer’s related orders.

Notice that properties you want to be lazy-loaded should be marked as virtual.

In our example, Customer.Orders was a virtual property. It wouldn’t have been lazy-loaded otherwise.

 

How Does Lazy-Loading Work?

Entity Framework loads entities on demand using dynamically generated proxy classes. These proxy classes are created at runtime and are derived from the entity classes. In our example, an entity like OrderProxy which inherits from Orderis  created at runtime and assigned to the Customer.Orders properties.

The dynamic proxies provide a transparent way to implement lazy loading by intercepting property accesses and loading related data as needed. This is achieved by marking the related property as virtual, which indicates that a proxy class can override it.

Dynamic proxies are generated at runtime based on the specific entity type. This enables Entity Framework to provide lazy loading behavior with minimal overhead, as the proxy classes are optimized for the specific entity types.

 

The Tradeoff

Like other decisions you make while developing software, there’s no one-size-fits-all solution for all scenarios, and the trade-off should be considered.

Next, we’ll see the tradeoffs between using and not using lazy loading in Entity Framework.

Pros and Cons of Lazy Loading

  • Pros:
    • Improved performance: By only loading data as needed, there is a smaller amount of data to transfer from the database to the application, leading to faster performance.
    • Reduced memory usage: Lazy loading helps to reduce the amount of memory required to store data, as it only loads the data being used at the time.
    • Ease of development: With lazy loading, developers can work with data in a more intuitive and natural way, as they can defer the loading of related data until it is actually needed.
    • Scalability: Applications that use lazy loading are better equipped to handle large amounts of data, as they can avoid loading all of it at once.
  • Cons:
    • Increased number of database roundtrips: Lazy loading can result in multiple database roundtrips, affecting performance, especially for complex data relationships.
    • Risk of increased memory usage: If not managed properly, lazy loading can lead to increased memory usage as more data is loaded over time.
    • Complexity: Lazy loading can add complexity to an application, as it may require more careful data loading and cache management.

 

Pros and Cons of Not Using Lazy Loading

  • Pros:
    • Predictable performance: By loading all data in a single query, the performance is more predictable and easier to manage.
    • Reduced complexity: By avoiding lazy loading, an application can be simpler and more straightforward, as there is no need to manage data loading and caching.
  • Cons:
    • Increased memory usage: Loading all data in a single query can result in increased memory usage, especially for large data sets.
    • Reduced performance: Loading all data in a single query can result in slower performance, especially for large data sets.
    • Reduced scalability: Applications that do not use lazy loading are not as well equipped to handle large amounts of data, as they must load all of it at once.

 

If you need lazy loading for only some entities and not all of them you can mark only the ones you want to load lazily.

Lazy Loading Without Proxies

It’s worth noting that Entity framework also provides an option that allows developers to lazy-load related data without proxies. To do so, you’ll need to inject an ILazyLoader object into entities. In our example, if we want to lazy load CustomersOrders, the Customer class must be implemented as follows.

You can learn more about dependency injection in this article.

You can find the source code for this article in this GitHub repository. You can clone it, set up the database, and run the tests. If you want to skyrocket your C# career, check out our powerful ASP.NET full-stack web development course that also covers test-driven development.

Conclusion

In conclusion, lazy loading is a valuable feature in Entity Framework that can provide benefits in terms of performance, memory usage, and ease of development. However, it also has some drawbacks, such as the potential for increased complexity and multiple database roundtrips. The decision to use or not to use lazy loading will depend on the specific requirements and constraints of each application. Generally speaking, it is important to consider the tradeoffs and choose the approach that best fits the application’s needs. The following table is a cheat sheet to help you decide where to use Lazy Loading.

  Using Lazy Loading Not Using Lazy Loading
Pros 1. Improved performance by only loading data as needed

2. Reduced memory usage

3. Ease of development

4. Scalability

1. Predictable performance

2. Reduced complexity

Cons 1. Increased number of database roundtrips

2. Risk of increased memory usage

3. Complexity

1. Increased memory usage

2. Reduced performance

3. Reduced scalability

Enter your email and we will send you the PDF guide:
Enter your email and we will send you the PDF guide