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.
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.
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 .
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.
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.
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.DbQuery
1[DataModel.Table12 AsNoTracking()' declared on type 'System.Data.Entity.Infrastructure.DbQuery
1[DataModel.Table2]' cannot be called with instance of type 'System.Data.Objects.ObjectQuery`1[DataModel.Table2]'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With