【问题标题】:Scope of AsNoTracking within LINQ query in Entity Framework实体框架中 LINQ 查询中 AsNoTracking 的范围
【发布时间】:2013-08-14 11:54:04
【问题描述】:

在 Entity Framework 的 LINQ 查询中使用 AsNoTracking 方法时,是否应该对每个表或整个查询使用它以禁用整个查询的更改跟踪?

1.针对整个查询

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

2。针对每张桌子

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

我的意图是禁用整个查询的更改跟踪,但如果不需要,我不想对每个表使用它。

MSDN 指的是该方法文档中的查询对象:

此方法通过调用底层的 AsNoTracking 方法来工作 查询对象。如果底层查询对象没有 AsNoTracking 方法,那么调用这个方法什么也做不了。

【问题讨论】:

    标签: entity-framework


    【解决方案1】:

    根据我刚刚所做的测试,这两个结果是相同的。使用 Table Level 或 QueryLevel AsNoTracking 会导致没有实体被保存在 ChangeTracker 中。但无论哪种方式,Table2 中的实体都不会放入 ChangeTracker 中,正如您在 WithtoutAsNoTracking 测试中看到的那样。

    假设您确实是从 t1 和 t2 查询数据。当我查询所有条目时,我添加了一个测试,仍然将单个 AsNoTracking 添加到查询中,没有条目被跟踪。不过,如果您将 AsNoTracking() 直接放在 table1 上,则不会跟踪 table1 和 table2 中的实体。

        [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));
            }
        }
    

    此外,我已从 join 子句中的 Table2 中删除 AsNoTracking,因为它会导致异常。

    System.ArgumentException:方法“System.Data.Entity.Infrastructure.DbQuery1[DataModel.Table12 AsNoTracking()' declared on type 'System.Data.Entity.Infrastructure.DbQuery1[DataModel.Table2]”不能使用“System.Data.Objects.ObjectQuery`1[DataModel.Table2] 类型的实例调用'

    【讨论】:

    • 这是一个全面的答案。谢谢。
    • 那么当你做一个join的时候,AsNoTracking()是没用的?
    • @Giox 完全正确。 AsNoTracking() 不影响连接
    • 即使没有 .AsNoTracking() 计数对我来说也归零(即使没有连接)。我不认为你的测试用例是一个好的。
    【解决方案2】:

    我刚刚创建了自己的测试。测试跟踪计数不是这样做的方法。你没有改变任何东西..结果总是零..我创建了一个速度测试。

    3个场景:每张表都用AsNoTracking(),select后用AsNoTracking(),然后不用AsNoTracking()

    获胜者.. 在选择。

    `

            DateTime noneStart = DateTime.UtcNow;
            var queryNone = await (from i in _db.inv
                                   join d in _db.dist on i.id equals d.invId
                                   select new { i, d }).Take(1000).ToListAsync();
            DateTime noneFinish = DateTime.UtcNow;
    
            TimeSpan nonSpan = noneFinish - noneStart;
            var countNone = _db.ChangeTracker.Entries().Count();
            _db.ChangeTracker.Clear();
    
            DateTime allStart = DateTime.UtcNow;
            var queryAll = await (from i in _db.inv.AsNoTracking()
                                   join d in _db.dist.AsNoTracking() on i.id equals d.invId
                                   select new { i, d}).Take(1000).ToListAsync();
            DateTime allFinish = DateTime.UtcNow;
            TimeSpan allSpan = allFinish - allStart;
            var countIndividual = _db.ChangeTracker.Entries().Count();
            _db.ChangeTracker.Clear();
    
            DateTime groupedStart = DateTime.UtcNow;
            var queryGrouped = await (from i in _db.inv
                                  join d in _db.dist on i.id equals d.invId
                                  select new { i, d}).AsNoTracking().Take(1000).ToListAsync();
            DateTime groupedFinish = DateTime.UtcNow;
            TimeSpan groupedTimeSpan = groupedFinish - groupedStart;
            var countGrouped = _db.ChangeTracker.Entries().Count();
            _db.ChangeTracker.Clear();
    
            var noJoin = await (from i in _db.inv
                                      select new { i}).Take(1000).ToListAsync();
    
            var countNoJoin = _db.ChangeTracker.Entries().Count();
            
            _db.ChangeTracker.Clear();
    
            Console.WriteLine($"AsNo @ Each Table Count: {countIndividual}");
            Console.WriteLine($"AsNo @ Select: {countGrouped}");
            Console.WriteLine($"No AsNo Count: {countNone}");
            Console.WriteLine($"No Asno & No Join Count: {countNoJoin}\n");
    
            Console.WriteLine($"AsNo @ Each Table Milli: {allSpan.Milliseconds}");
            Console.WriteLine($"AsNo @ Select Milli: {groupedTimeSpan.Milliseconds}");
            Console.WriteLine($"No AsNo Milli: {nonSpan.Milliseconds}");
    
            Assert.AreEqual(0, countIndividual);
            Assert.AreEqual(0, countGrouped);
            Assert.AreEqual(0, countNone);
            Assert.AreEqual(0, countNoJoin);
        `
    

    结果:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多