Performance issues with multiple includes and large object graphs - Entity Framework

Entity Framework (EF), Microsoft's ORM answer to nHibernate, is an excellent tool. I've used it many times in many projects. It's easy to get started and set up, it's versatile and has good support. Unfortunately, as with every other tool, there are pitfalls. The larger a project gets, the harder it becomes to use EF straight out-of-the-box. As your objects and relationships grow, your queries need to become more intelligent. More refined. There are many ways to mitigate performance issues, BDD, multiple contexts, query optimization, AutoMapper, etc. I could probably do another post or posts just on this subject! And remember:

Just because LINQ supports it, it doesn't mean it's a good idea

Today I'll show you how to quickly make performance improvements in your EF query implementation. There are 2 major benefits in this approach:

  1. You don't have to make changes to your data model
  2. It's quick and easy to put in place

However, as with everything else, there is a downside too. The suggested solution applies only to read-only operations. This is not the end of the world though, as typical database workflows have a standard format. I will use a typical web page as an example:

1. Query Data -> 2. Display Data -> 3.Select item to interact with -> 4. Edit -> 5. Save

EF in the context of web operations is special. Developers tend to forget that EF operates in a disconnected context when used on the web. Each operation (1-5) is disconnected as far as EF is concerned. Each time you have to fetch/bind your object graph to perform the necessary operation. Consequently, it's easy to optimize certain parts of the above workflow using the read-only dbContext. Parts 1 and 3 are prime candidates. The read-only dbContext takes advantage of the following configuration settings:

  • Disable Lazy Loading: Configuration.LazyLoadingEnabled = false;
  • Disable AutoDetectChanges: Configuration.AutoDetectChangesEnabled = false;
  • Disable Proxy Creation: Configuration.ProxyCreationEnabled = false;
  • Disable Entity Caching using the IQueryable AsNoTracking() method

Show me the code!

I've included the sample ReadonlyDbContext for reference below:

The ReadonlyDbContext class should derive from your base DbContext. 2 things are important:

  1. The SetConfigurationOptions() method where we set up the properties I mentioned earlier.
  2. Calling Save() will throw an exception to guard against unwanted behavior

You use the query-optimized dbContext like this:

I hope this will help you improve your EF queries but remember that this is only one of the many performance optimization tweaks you can do. Make sure you investigate all available options and don't be afraid to refactor your code. You want your DAL to be as robust and efficient as possible.

Further reading

  • Share this post on