• Home
  • Tutorials
  • Development Tools
  • Contact Us

Developing Software

Mastering Software Craftsmanship

Why Is Entity Framework with ASP.NET Slow?

22nd August 2014 by @developingsoft

Do you have a slow running ASP.NET Web Application? There’s a good chance it’s because of lazy loading, an Entity Framework feature that’s enabled by default. In my opinion, you should not use lazy loading for web applications. In this post I will explain why lazy loading can slow down performance and what you can do instead.

What is Lazy Loading?

Lazy loading is a design pattern that delays the initialisation of an object until the point it’s first accessed. It’s purpose is to make your application use less memory and increase efficiency by reducing the amount of data transferred to/from the database.

Unfortunately, it can do more harm than good. Especially if someone on your team is not aware of lazy loading and what’s going on behind the scenes.

The hidden problem that lazy loading causes is the nasty select N+1 issue. Lets take a look at an example of Entity Framework lazy loading and what causes a select N+1 issue.

Entity Framework Lazy Loading

In the following example, imagine you have a User that can have many Roles. The Entity Framework model for this use case might look something like the following:

public class User
{
    public int Id { get; private set; }
    public string Name { get; set; }
    public virtual ICollection<Role> Roles { get; set; }
}

public class Role
{
    public int Id { get; private set; }
    public string Name { get; set; }
}

public class MyDbContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Role> Roles { get; set; }
}

Now lets say you have a User called Bob and a User called Smith, and they both have the Admin, Editor, Author and Guest Roles. As an example, lets say you wanted to print all the Users Names and Roles. The code that would cause a select N+1 issue might look something like this:

using (var context = new MyDbContext())
{
    var users = context.Users.ToList(); // first SQL query
    foreach (var user in users)
    foreach (var role in user.Roles)
    {
        // SQL query for each user
        ViewBag.Message += String.Format("User: {0} Role: {0},", user.Name, role.Name);
    }  
}

OK, so the above example is not likely to come up very often, but I have seen/inherited projects that are riddled with these select N+1 issues. This example would generate 3 SQL queries, 1 to get the Users and 1 for each call to the users Roles.

And that’s only for 2 Users.

You can see how much damage to an applications performance Entity Framework lazy loading could cause. How do we solve the issue?

Solving the select N+1 issue

To fix the issue I recommend always using Include when you need to access the child entities. The above improved example would look like this:

using (var context = new MyDbContext())
{
    var users = context.Users.Include(i => i.Roles).ToList();
    foreach (var user in users)
    foreach (var role in user.Roles)
    {
        ViewBag.Message += String.Format("User: {0} Role: {0},", user.Name, role.Name);
    }
} 

The call to Include in the above example makes the code run only 1 SQL query. This drastically improves the performance.

The best execution time on my machine for the first example (lazy loading) was 2.1 ms. The best time for the second example (no lazy loading) was 0.80 ms.

Disabling Lazy Loading

To make sure no one on your team accidentally causes an N+1, I would recommend turning off Lazy loading. This can be done by setting the Configuration.LazyLoadingEnabled property to false in your DbContext class constructor.

Now after doing this, you have to remember that queries that don’t have a call to Include will cause an exception when trying to access the child entities. So in the first example (lazy loading) you would get an exception when trying to loop through the users roles because Roles would be null.

Personally, I would rather scratch my head as to why I’m getting null child entities rather than why the performance is shocking. As soon as you see a null reference exception, you know there is an Include missing somewhere.

So when should you use Lazy Loading?

For web applications, I’ve yet to find a reason for using Lazy loading. I think this is because web applications are stateless, which makes lazy loading pointless.

If you want to select only a limited amount of data, there are better ways of doing this by using projection queries.

It probably makes more sense to use lazy loading for applications that are stateful (desktop). However, personally, I don’t think its worth the hassle of introducing possible performance issues.

Disable lazy loading, use projection queries, and your performance will rocket.

Share this on:

Filed Under: Tutorials Tagged With: ASP.NET MVC, C#

Search

Advertisement

Newsletter

Subscribe now to receive practical tips on how to become a better software developer.

Free - No Spam - 100% Email Privacy

Featured Posts

Abstract Factory Pattern: C# Example Using the Unity Game Engine

23 Software Design Patterns That Will Make You a More Effective Programmer

How to Deploy an ASP.NET Core Website to Ubuntu with Git

How to Run an ASP.NET Core Website in Production on Ubuntu Linux

How to Install the Edimax Wireless nano USB Adapter on Windows IoT Core for Raspberry Pi

How to Convert a Post Title into a Friendly URL (Slug) in C#

How to Convert Markdown to HTML in ASP.NET Core

How to Send an E-Mail with ASP.NET Core and Mailgun

How to Generate a Sitemap in ASP.NET MVC and ASP.NET Core

How to Create an MD5 Hash of a String in C# and Displaying a Gravatar Image

© 2014–2025 Developing SoftwareTerms • Privacy