In previous article, we have seen how to save related entities. The post explains how categories association with post can be saved. Same concept can be applied to saving tags and comments. In this article, we are going to have look at how to retrieve related data.
Types of Loading
We have already seen that relationships can be defined by using navigation properties. There are various ways which can be used by frameworks like EF core to load related data. There are three different approaches
- Lazy Loading
- Eager Loading
- Explicit Loading
In following sections, we will try to discuss more about these three approaches and how to use them.
In this approach, the principal entity is first read, but related data is not read at that time. When navigation property is accessed for first time, at that time, a query is issued to database to load related data.
This approach may be helpful to reduce the amount of data which is being retrieved by the first request, but on the other hand, it may also result in chattiness, causing performance issues.
There are different ways by which lazy loading can be implemented. First approach is to use NuGet package – Microsoft.EntityFrameworkCore.Proxies – and then call UseLazyLoadingProxies method. This method can be called from two places
- either from
OnConfiguringmethod in derived DbContext class
- or from
Startup.ConfigureServicesmethod, when application calls AddDbContext method.
Both of the these are shown in the code snippet given below.
Once this is done, EF core will automatically apply lazy loading to the navigation properties which can be overridden. So if you declare virtual navigation property, it would automatically use lazy loading.
Another approach can be to inject a service in entity to load the related data when
navigation property is accessed.
This approach loads data in exactly opposite manner as compared to lazy loading. As the name suggests, the principal entity and its related data are load together in this approach. This type of loading generally issues a JOIN query to the database to load related data.
There might be couple ways by which this can be implemented in code. One way is to issue a single command to load principal entity and all its related data. This can be achieved by using
Another way is to use multiple queries to load related data. So, the idea is, to retrieve some of the data in separate queries. EF core will automatically take care of putting the related data in appropriate navigation properties. In such approach, the EF core should use Load method to load data instead of methods like ToList or SingleOrDefault which return the object.
In this case, firstly, a principal entity is loaded, but related data is not loaded at that time. Then a navigation property can be used to explicitly load the related data of specific type. Like multiple queries in
Eager Loading, this would also result in multiple database queries.
Which one should be preferred ?
Next obvious question is – if there are several approach, how should one decide the best approach for an application ?
The answer to this question depends on overall design of your application.
Let’s consider our blog application. A blogpost is related to tags, categories and comments. But when a blogpost is shown (whether in edit mode or read only mode), all its related data needs to be presented on the same page. A blog application cannot say that it would load comments on blog post later when user clicks on something. There might be pagination applied to the comments section, but it would still show some comments in beginning. So, in this case, it makes sense to use eager loading to load all related data together with a blogpost entry.
Some applications have master view and detailed views. Master views show only couple of properties while detailed view loads all related data. In such cases, it might be better idea to create two read calls – one which reads only principal entity collection and other which uses eager loading to read all related data. Some may also prefer lazy loading in this case to load the related data once detailed view is opened.
So, to answer above question, few more questions should be asked:
- Does application needs related data right away ?
- If not right away, does application needs related data in processing of current request ?
- Does application needs all navigation properties or only few of them ?
- Does application needs related data only based on principal entity selected ?
Answers to these questions should help us to decide which approach should be used. In my opinion, once one of the approach is selected, it should also be reviewed periodically to ensure best application performance.