Skip to main content

Entity Framework Optimizations

Entity framework does not have great performance when dealing with large batches of data. We've compiled this list as a reference so that our batch operations can be efficient as possible.

Please Read these Articles

https://weblog.west-wind.com/posts/2014/dec/21/gotcha-entity-framework-gets-slow-in-long-iteration-loops 
https://weblog.west-wind.com/posts/2013/Dec/22/Entity-Framework-and-slow-bulk-INSERTs 

Disable Auto Detecting Changes

see https://docs.microsoft.com/en-us/ef/ef6/saving/change-tracking/auto-detect-changes 

using (var context = new BloggingContext())
{
    try
    {
        context.Configuration.AutoDetectChangesEnabled = false;

        // Make many calls in a loop
        foreach (var blog in aLotOfBlogs)
        {
            context.Blogs.Add(blog);
        }
    }
    finally
    {
        // make sure you re enable AutoDetectChangesEnabled before calling SaveChanges
        context.Configuration.AutoDetectChangesEnabled = true;
        await context.SaveChangesAsync();
    }
}

Bloated DbContext

With Entity Framework, you have a dbContext object that tracks all the entities you've read from the database and changes that have been made to them. If it starts to track too many entities you can start getting pretty slow performance.

There a several thanks that can be done to address this issue.

.AsNoTracking()

List<DbNodes> childNodes = UtopiaDB.DbNodes.Where(i => i.ParentID = 1).AsNoTracking().ToListAsync();

When you use .AsNoTracking() the entities that get returned will not be tracked by the dbContext. You should use this when you are querying data from the db that is read only.

Re-Create DbContext Object

The easiest way to get past a bloated dbContext is to create a new dbContext object.

This is difficult in our Utopia solution because create one dbContext object per session, so unless a new session is created, a new dbContext object cannot be created.

To address this we have added code to to detach all entities from the dbContext

UtopiaDB.DetachEntitiesFromUtopiaDB();

The intent behind this code was to have the same effect as creating a new DbContext object.

Smaller Batches

Typically we've seen better performance when we process things in smaller batches (500 items or less), call 'SaveChangesAsync()', then detach all entities from the DbContext object, and process another small batch.