C#

Entity Framework .AsNoTracking() – why & how (EF and EF Core)

AsNoTracking() is a powerful method from DbExtensions class. And for sure – the method you should know and use 😉.

Why should I use it?

In short – when we call AsNoTracking(), less data is cached and tracked (we will talk about it later). And of course, the more records we retrieve from the database, the more RAM we spare.

 

How to use it?

You simply call .AsNoTracking on context object, like in the bellow example:

 

What’s going on under the hood?

In standard scenario, all the entities selected from a database via EF are tracked. And tracking means that context ‘observes’ the tracked object and knows if it was changed. Thanks to that, when context uses tracking and we call context.SaveChanges(), changes will be applied to database. We don’t have to do some voodoo magic and attach entity or change its state. EF knows how to do its job.

So, when we call .AsNoTracking() our entity will be not tracked (wow, what a surprise! 😉 ). Although we change fields of our entity, nothing will be updated after calling context.SaveChanges().

It’s not a problem here, because we see that .AsNoTracking() was called. And that’s how you set this in EF. Thanks God, we cannot turn off tracking in EF globally.

But we can do something similar to that in EF Core 2.0. To turn off tracking for the whole context, we write the below code:

Of course, we can write this line in some factory method and… Make our colleagues to spend some time on investigating why they cannot update their entities in database. Evil enough, huh? 😀

And then we create our context like if nothing special happened. Just another boring office day, my friends :P.

 

How to update an entity when tracking is turned off?

Sometimes it’s beneficial to retrieve a record from database as non-tracking, even though you suspect to change and submit it a few moments later. I’m talking here about the situation when logic of your app requires some extra checking and the entity will be updated only in some specific scenario (ex. when logged user is privileged to do some operations or when shopping cart status is ‘not accepted’ etc). In this situation, we need to update an object in database only in some specific scenario, so it’s better to non-track it and do some voodoo when it’s needed.

How to save changes to DB when .AsNoTracking() was called on object?

Simply attach it to the context and tell EF that our entity has changed!

  • In EF Core we write the below line:

Like in the example below:

  • In EF (not Core) we act the same, but instead of calling .Attach() on context, we call .Entry().

Like in the below example.

What is more, we can attach the entity once and then change this object many times. And of course call SaveChanges() every time you want it to go to the DB.

Cherry on the top

Quite interesting may seem the fact, that tracking (and turning tracking off) works on anonymous types too.

  • In the below example, the field Name of Order entity will be updated:

  • And in the below example, the Number will be not updated in Order entity:

 

Summary

Use AsNoTracking() whenever you:

  • retrieve the data that will be not changed (ex. a read-only list of books etc).
  • retrieve the record that may be updated but not in every logical path

And if you really need to turn off tracking on the context level, especially in some factory-like method, make it noticeable (naming method CreateNotTrackedDbContext() would be just awesome 😉 ).

 

 

Feature photo by Jason Blackeye

Share this: