Reputation: 5872
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.
Upvotes: 39
Views: 16640
Reputation: 2687
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]'
Upvotes: 49