Entity framework strategies when loading data4 min read

There are several types of loading data using Entity Framework.
Those are:

  • Lazy Loading
  • Eager Loading
  • Explicit Loading

You will also come across one problem when using one of EF strategies.
That is N+1 problem.

But more on that later. Let’s talk about types of loading in EF!

Lazy loading

It’s used to retrieve data which is needed on demand.
This makes loading a data less heavy for our app.

But there is always a but. Skip to When to use lazy loading if you want to know asap!

First, let’s take a look at our example.

I.e.: imagine we have a class like this one:

class Company {

​	public virtual ICollection<Project> Projects {get;set;}

}

As you can see, to enable lazy loading for our property we used virtual keyword.

In our app logic we have something like this:

var context = new AppContext();

var company = context.Company.Single(c=>c.Id == 13);

foreach(var project in company.Projects){

​	Console.WriteLing(project.Name);

}

Whenever we use Single, SingleOrDefault, First, FirstOrDefault, Max or Count we immediately cause query execution.

But in our case, company doesn’t have Projects initialized.

So in our foreach block, EF will send additional query to the DB to get what we need, in this case Projects is what we need.

As you can see, we use here Lazy Loading. Since Projects are not loaded immediately but loaded when we need to access them.

When to use lazy loading

We use lazy loading only when we expect to have a big number of data which would potentially slow down our app when retrieving data.

Use it only in desktop applications since in web apps we don’t have context object living in the memory while we are requesting data over rest services.


Thus said, using lazy loading would decrease our web app performance due to unnecessary round trips.

Disabling lazy loading

  1. By not using virtual keyword for property.
    1. which is complicated while we need to take care for each navigation property to follow this rule
  2. By configuration
    1. In AppContext() constructor we add this line of code:
this.Configuration.LazyLoadingEnabled = false; 

Eager Loading

It’s of course, the opposite thing from Lazy Loading. Which means that data is prefetched from the DB.

In our example we want to prefetch data for Project Manager. And there are two ways to achieve this.

The good way and the bad way!

The bad way:

var context = new AppContext();

var projects = context.Projects.Include("Manager").ToList();

foreach(var project in projects){

​	Console.WriteLing(project.Name, project.Manager.Name);

}

Why is this the bad way?

Well, it’s obvious we use magic string here. So typo might happen or perhaps our property isn’t named that way and our code would break!

So to avoid this kind of mistakes we will use System.Data.Entity namespace and use lambda expression.

The good way:

var context = new AppContext();

var projects = context.Projects.Include( p => p.Manager).ToList();

foreach(var project in projects){

​	Console.WriteLing(project.Name, project.Manager.Name);

}

Why is this the good way?

If for some reason our property changes we would be given an compile error. So it’s much easier to debug and fix the problem!
Additionally when using refactor inside Visual Studio, we could easily rename it (which is not the case with magic string).

The negatives

If using too many Includes a lot’s of data would eventually end up in memory. And perhaps we don’t need all that data.

Explicit Loading

We use it when using Eager Loading are becoming more and more complex!

So this way we manually preload data which we need.

Main differences between Eager Loading and Explicit Loading:

Eager LoadingExplicit Loading
uses joinsmultiple queries
one round tripmultiple round trips

Here is an example:

var context = new AppContext();

var manager = context.Manager.Single( m => m.Id = 3);

context.Projects.Where( p => p.ManagerId == manager.Id).Load(); // hence using LOAD() method

foreach (var project in manager.Projects){

​	Console.WriteLing(project.Name);

}

Benefits

We get much simpler query since we avoid using bunch of joins inside our query.

We can apply filters.

Negatives

Multiple round trips to the database. Which maybe in some cases might be more efficient than one query with multiple joins.

N+1 problem

Is a common problem when using lazy loading and getting N entities with their related entities. Since we will end up with N+1 queries.

I.e.:

var context = new AppContext();

var projects = context.Projects.ToList(); // this is query number 1

foreach (var project in projects){ // foreach each project we will get additional query (lazy loading) to retrieve Manager and his name

// this means if we have N projects we will end up with N queries for projects and that above +1 query to retrieve all projects

​	Console.WriteLing(project.Name , project.Manager.Name);

}

Negatives

Using lazy loading and causing this kind of problem means we will end up with bunch of unnecessary queries which will overload our database and cause performance issues.

Final words

Which strategy to use and when depends solely on a specific situation and a developer. So each developer should be aware of a potential performance issues when choosing appropriate strategy.

Leave a Reply

Your email address will not be published. Required fields are marked *