Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scope of AsNoTracking within LINQ query in Entity Framework

When utilising the AsNoTracking method within a LINQ query in Entity Framework, should it be used against each table or the query as a whole in order to disable change tracking for the entire query?

1. Against the entire query

var query = (from t1 in db.Table1             from t2 in db.Table2.Where(o => t1.ConditionId == o.ConditionId)             select t1).AsNoTracking() 

2. Against each table

var query = (from t1 in db.Table1.AsNoTracking()             from t2 in db.Table2.AsNoTracking().Where(o => t1.ConditionId == o.ConditionId)             select t1) 

My intention is to disable change tracking for the entire query but don't want to use it against each table if it isn't required.

MSDN refers to a query object in the documentation for this method:

This method works by calling the AsNoTracking method of the underlying query object. If the underlying query object does not have a AsNoTracking method, then calling this method will do nothing.

like image 429
Nick Avatar asked Aug 14 '13 11:08

Nick


People also ask

What is the use of AsNoTracking in Linq?

The AsNoTracking() extension method returns a new query and the returned entities will not be cached by the context (DbContext or Object Context). This means that the Entity Framework does not perform any additional processing or storage of the entities that are returned by the query.

Where does AsNoTracking go?

It doesn’t really matter where you call the AsNoTracking . It can be at the start, in middle or at the end before calling an immediate method such as ToList() . In all cases, the same behavior will happen. All entities will not part of the ChangeTracker .

How do you get entities back from a query without getting tracked by the context?

The AsNoTracking() extension method returns a new query and returned entities do not track by the context. It means that EF does not perform any additional task to store the retrieve entities for tracking. We can also change the default behavior of tracking at context instance level.

What is AsNoTracking in Entity Framework Core?

The AsNoTracking() method returns a new query where the change tracker will not track any of the entities that are returned. If the entity instances are modified, this will not be detected by the change tracker, and SaveChanges() will not persist those changes to the database.


1 Answers

Based on a test I've just made both results are the same. using Table Level or QueryLevel AsNoTracking result in no entities being hold into tine ChangeTracker. But either way, entities from Table2 are never put inside of the ChangeTracker, as you can see in the WithtoutAsNoTracking test.

Base on the assumption, that you are indeed querying data from t1 and t2. I've added a test when I'm querying all entries are still with a single AsNoTracking added to the query, no entry is tracked. Still if you put the AsNoTracking() directly on table1, the entities from table1 and from table2 aren't tracked.

    [TestMethod]     public void QueryLevelAsNoTracking()     {         using (var context = new DbContext())         {             var query = (from t1 in context.Table1                          from t2 in context.Table2.Where(o => t1.ConditionId == o.ConditionId)                          select t1).AsNoTracking();              var list = query.ToList();             Assert.AreEqual(0, context.ChangeTracker.Entries().Count());         }     }      [TestMethod]     public void TableLevelAsNoTracking()     {         using (var context = new DbContext())         {             var query = (from t1 in context.Table1.AsNoTracking()                          from t2 in context.Table2.Where(o => t1.ConditionId == o.ConditionId)                          select t1);              var list = query.ToList();             Assert.AreEqual(0, context.ChangeTracker.Entries().Count());         }     }      [TestMethod]     public void WithtoutAsNoTracking()     {         using (var context = new DbContext())         {             var query = (from t1 in context.Table1                          from t2 in context.Table2.Where(o => t1.ConditionId == o.ConditionId)                          select t1);              var list = query.ToList();             Assert.AreEqual(7, context.ChangeTracker.Entries().Count(x => x.Entity is Table1));             Assert.AreEqual(0, context.ChangeTracker.Entries().Count(x => x.Entity is Table2));         }     }       [TestMethod]     public void QueryLevelAsNoTracking_SelectAllData()     {         using (var context = new DbContext())         {             var query = (from t1 in context.Table1                          from t2 in context.Table2.Where(o => t1.ConditionId == o.ConditionId)                          select new                                     {                                             t1,                                             t2                                     }).AsNoTracking();              var list = query.ToList();             Assert.AreEqual(0, context.ChangeTracker.Entries().Count());         }     }      [TestMethod]     public void Table1AsNoTracking_SelectAllData()     {         using (var context = new DbContext())         {             var query = (from t1 in context.Table1.AsNoTracking()                          from t2 in context.Table2.Where(o => t1.ConditionId == o.ConditionId)                          select new                          {                              t1,                              t2                          });              var list = query.ToList();             Assert.AreEqual(0, context.ChangeTracker.Entries().Count(x => x.Entity is Table1));             Assert.AreEqual(0, context.ChangeTracker.Entries().Count(x => x.Entity is Table2));         }     } 

Also, I've remove the AsNoTracking From Table2 inside of the join clause because it was causing an exception.

System.ArgumentException: Method 'System.Data.Entity.Infrastructure.DbQuery1[DataModel.Table12 AsNoTracking()' declared on type 'System.Data.Entity.Infrastructure.DbQuery1[DataModel.Table2]' cannot be called with instance of type 'System.Data.Objects.ObjectQuery`1[DataModel.Table2]'

like image 164
Alexandre Rondeau Avatar answered Sep 23 '22 02:09

Alexandre Rondeau