EF Core Lets Us Finally Define NoTracking DbContexts

Way back in 2012, I added a feature request to EF6 to allow us to define a context that will never track entities that it retrieves from the database.

(Support Read-Only Context or DbSet)

This is instead of having to add AsNoTracking to all of your queries if you have a DbContext you are using for read-only data. Or more importantly, if your DbContext is being used for data that’s going to be disconnected and therefore never tracked post-query. That means a Web API or service or a controller. Tracking can be expensive if you are retrieving a lot of data and have no plans to update it. And having to remember to add AsNoTracking to every query is a PIA.

I just discovered that this is possible with EF Core and I think it was even in the EF Core 1.0 release!

There is a ChangeTracker property called QueryTrackingBehavior that takes a QueryTrackingBehavior enum whose options are NoTracking and TrackAll.

There are plenty of places to use it, but the one I’m excited about is to place it directly in the constructor of a DbContext to make that context default to never track any entities.

public class BookContext : DbContext
{
  public BooksReadOnlyContext() { 
    ChangeTracker.QueryTrackingBehavior = 
       QueryTrackingBehavior.NoTracking;
  }
 public DbSet<Book> Books {get;set;}
 etc ...

A quick test where I retrieved some books and the inspected the ChangeTracker.Entries returned 0, to show that this was doing what I’ve been dreaming of for over 5 years! Thanks EF team!

 Console.WriteLine(
   $"Tracked Entities: {context.ChangeTracker.Entries().Count()}");

Another point to be aware of is that just as you have always been able to use the DbSet’s AsNoTracking method to turn off tracking for a particular query, you can now use AsTracking to turn on tracking for a particular query.

13 thoughts on “EF Core Lets Us Finally Define NoTracking DbContexts

  1. Hi Julie,

    Do you think there is any performance advantage in doing this with EF 6 (in a Web API for immediate JSON serialization):

    var productsForCategory = (from p in context.Products.AsNoTracking()
    where p.Category.CategoryName == selectedCategory
    select p).ToList();

    Over this

    var productsForCategory = (from p in context.Products
    where p.Category.CategoryName == selectedCategory
    select p).ToList();

  2. Hi Julie,
    Reading your post I remembered myself learning EF basics a while ago and thinking about entities tracking for simple blog.
    For example if we have 3 tables in our database
    BlogPosts
    PostComments
    CommtoPostMapping
    Is it make sense to create two DbSets one for getting posts (read-only) and another one for comments (read-write), or it simplier to disable tracking of queary when getting posts from database just to display them on the website?
    Thx,
    Sergey Sypalo | sypalo.com

  3. Am I wrong? I think that was always possible in EF6 using the following code in the ctor of the context:
    Configuration.AutoDetectChangesEnabled = false

    1. no that’s different. That just determines if EF goes to update the state in the change tracker immediately when you make a change to a tracked object.

  4. In EF.Core 1.1, is there better way than below to use both FindAsync and AsNoTracking? I cannot seem to combine .AsNoTracking().FindAsync(id).

    “`
    var previousBehavior = _context.ChangeTracker.QueryTrackingBehavior;
    _context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
    var student = await _context.Students.FindAsync(id);
    _context.ChangeTracker.QueryTrackingBehavior = previousBehavior;
    if (student == null)
    {
    return NotFound();
    }
    “`

Leave a Reply

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