Today, I wanted to talk about eager loading versus lazy loading in entity framework. This is a very important architecture decision when initially setting up entity framework and has come up in quite a few projects over the years.
I decided to blog about the two options because there is often misconceptions that revolve around these two options and how they work and interact with other .NET extensions. There are several ways to accomplish toggling the two options, but I find the most common way that causes confusion is when and how to use the virtual keywords on your navigation properties.
What exactly is eager and lazy loading?
Eager loading and lazy loading are common terms used in software development that define at what point data is loaded into an object. Even though a field is created and a calculation has been assigned to it, the calculation is not run until some predefined event is triggered.
In entity framework this related to when a navigation property is given a value or when a SQL query will be run. I often as a question in interviews what the difference is between IQueryable and IEnumerable as it related to EF and SQL queries, but we can leave that for a different blog entry. Today, we will focus on the navigation properties scenario.
So what are they and how do we use them?
So what are these mysterious and commonly misunderstood entity framework options? Good question . Eagar loading means that you want Entity Framework to load the data when you want it to and not when it thinks is the best time to. Usually, when you want to eagerly load data, it’s because you need it for some column in the returned data that has some relation to another query (maybe an Id from a newly inserted row. Entity can return this, but maybe for some reason you aren’t doing this). Here is an example of eagerly loading the data.
public Employee GetEmployeeById(int id)
{
using (var dbContext = new Blog_EFEntities())
{
var employee = dbContext.Employees.FirstOrDefault(p => p.EmployeeId == id);
return employee;
}
}
The code above shows a method that creates the Entity Framework context with a using. This is good to use when you are creating custom contexts because as soon as you are outside the curly braces for the using, the context is disposed of for you to prevent memory leaks. I typically use repository and unit of work patterns to handle this, but it is great for smaller applications. Also for blog posts .
Inside the using, we are taking the context and requesting the first or default of the employees found with an Id of whatever the caller passes in. This takes the IQueryable and converts it into a concrete type. In this case an Employee object (table in the database). This is eager loading because you are asking entity to return you the data immediately, not when it feels a good time to do it.
There are problems with this method. When you have this code set up and maybe you get this data and then use it based some other check statements. Well, you just called the database for no reason. Now in this case, it’s not a big deal because it will only ever be one record, but what if you were getting all employees that were active and there were 600,000 of them? That might raise an issue. With that said, I tend to align more with this pattern because I like to have control of when data is being returned especially in the next section where we will discuss where this fits in with Navigation Properties.
How does this relate to Navigation Properties?
Good question! Navigation Properties in EF are the properties of a class that relate to another class/table. In database speak, foreign relationships. For example, in the example above, we have a Person class as our abstract and an Employee class that has a foreign relationship to the Person class. Here are the classes:
public partial class Person
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Person()
{
this.Employees = new HashSet<Employee>();
}
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Employee> Employees { get; set; }
}
public partial class Employee
{
public int EmployeeId { get; set; }
public int PersonId { get; set; }
public string Title { get; set; }
public string Department { get; set; }
public virtual Person Person { get; set; }
}
You will notice, that there is a Person.Employees property that returns a collection of employees. This is a Navigation Property. It allows the developer to get a list of Employees using a LINQ query through the navigation of a Person object. Some code for this would be something like:
public List<Person> GetEmployees()
{
using (var dbContext = new Blog_EFEntities())
{
var employees = dbContext.People.Where(x => x.Employees.Any());
return employees.ToList();
}
}
Here we are using the People object (pluralized version of Person table) and navigating through the Employees table to return any people that contain Employees.
Now, using the above examples, lets say that we did not do a ToList() on the returned variable employees and instead left it an IQueryable. When the caller received the result, until it calls the ToList() or something else that makes it become a concrete type, entity framework will be lazy and not make the call to the database. Pretty cool huh? What’s even cooler is that when the call is finally made, an inner join is made to get you Employee navigation property data as well.
But now, lets say that we want a list of all the People with the first name that starts with a ‘J’, but don’t care about the Title or Department because this is just a dropdown of name value pair. In the current structure, the virtual will always return the employee information which may be quite a bit of data depending on tables size. This is especially important in a web platform.
To get rid of this, you would get rid of the virtual keyword on the classes navigational properties. Then, whenever you want to get the employees, you can do make a call to do so using the include method in LINQ.
public List<Person> GetEmployeesWithInclude()
{
using (var dbContext = new Blog_EFEntities())
{
var employees = dbContext.People.Include("Employee").Where(x => x.Employees.Any());
return employees.ToList();
}
}
You will notice that Include uses magic strings, which I am not a fan of. There are plugins on Nuget that will override this method. I created my own implementation that I will share in another post. Maybe I’ll update this one. This is getting a little long, so I may not.
I hope this has helped clear some confusion on the options for eager and lazy loading in Entity Framework.
References:
http://stackoverflow.com/questions/5597760/what-effects-can-the-virtual-keyword-have-in-entity-framework-4-1-poco-code-fi
Happy Coding .