35

在 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 方法,则调用此方法将不会执行任何操作。

4

2 回答 2

46

根据我刚刚所做的测试,两个结果是相同的。使用 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:1[DataModel.Table12 AsNoTracking()' declared on type 'System.Data.Entity.Infrastructure.DbQuery无法使用“System.Data.Objects.ObjectQuery`1[DataModel.Table2]”类型的实例调用方法“System.Data.Entity.Infrastructure.DbQuery 1[DataModel.Table2]”

于 2013-08-14T12:38:11.927 回答
0

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

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);
    `

结果: 在此处输入图像描述

于 2021-10-21T16:33:11.620 回答