By default related objects are not loaded immediately , they are loaded on demand when we access them.
Carefully observe the relationship between tables shown below.
1. Category and Post:- have a one-to-many relationship. This means there can be several Posts in the same category.
2. Post and comments:- have a one-to-many relationship, which means there can be many comments on a Post.
3. User and Comment :- have a one-to-many relationship , means a user may post several comments on a Post .
Example 1. Fetch number of posts in each category.
public class Program
{
public static void Main()
{
var db = new BlogDbContext();
var categories = db.Categories.ToList();
foreach(var cat in categories)
{
Console.WriteLine("Category :{0} | Number of Posts :{1}", cat.CategoryName,cat.Posts.Count());
}
Console.ReadLine();
}
}
In the above example we are first loading all the categories into the memory using the ToList() method which causes immediate execution, but even with the immediate execution we couldn't load the related objects , means db.categories.ToList() query only loads the category objects into the memory and not the related post objects.
When we iterate over the query variable and fetch any property the related object then only the linq provider fires the necessary T-SQL to the database and loads the related object into the memory, in our case cat.Posts.Count() statement loads the post object (count) into the memory.
Output:
N+1 Issue
Lazy loading causes n+1 issue , means to get N entities and their related entities you will end up with n+1 query requests to the database. The diagram shown below explains it in more details.
How does Lazy loading work behind the scene?
When we generate entity then for any type of relationship, corresponding navigation properties are also created , when you look closely you will find all navigation properties are marked as virtual , see below entities generated by Entity Framework.
If you have a little knowledge about OOPs polymorphism concept then you would know that virtual keyword is used to achieve run time polymorphism means we can change the behavior of a method / property at run time by simply overriding them. The same concept is being applied here , at run time the navigation properties change their behavior something like shown below.
So , with each iteration a new request goes to the server to load the related entities , which results in too many requests and degrade the performance, so don't use Lazy loading until you really need it.
How to disable Lazy loading
Lazy loading is by default enabled, in order to disable it you have two options.
1. Delete the virtual keyword from navigation properties.
2. Disable it for the whole project by configuring it in the DbContext as shown below.