【问题标题】:Does it matter where AsNoTracking in Entity Framework is called在实体框架中调用 AsNoTracking 的位置是否重要
【发布时间】:2016-02-22 12:17:47
【问题描述】:

在编写实体框架查询时调用 AsNoTracking 方法的位置是否重要?例如

var matchingCustomers = context.Customers.AsNoTracking().Where(n => n.city == "Milan").Skip(50).Take(100).OrderBy(n => n.Name).ToList();
var matchingCustomers = context.Customers.Where(n => n.city == "Milan").AsNoTracking().Skip(50).Take(100).OrderBy(n => n.Name).ToList();
var matchingCustomers = context.Customers.Where(n => n.city == "Milan").Skip(50).AsNoTracking().Take(100).OrderBy(n => n.Name).ToList();
var matchingCustomers = context.Customers.Where(n => n.city == "Milan").Skip(50).Take(100).AsNoTracking().OrderBy(n => n.Name).ToList();
var matchingCustomers = context.Customers.Where(n => n.city == "Milan").Skip(50).Take(100).OrderBy(n => n.Name).AsNoTracking().ToList();
var matchingCustomers = context.Customers.Where(n => n.city == "Milan").Skip(50).Take(100).OrderBy(n => n.Name).ToList().AsNoTracking();

我喜欢将它添加到语句的末尾,但在这样调用 ToList 之前:

var matchingCustomers = context.Customers.Where(n => n.city == "Milan").Skip(50).Take(100).OrderBy(n => n.Name).AsNoTracking().ToList();

【问题讨论】:

    标签: c# asp.net-mvc performance entity-framework


    【解决方案1】:

    不,没关系:(source)

    应用了 NoTracking 的新查询,如果不支持 NoTracking,则为源查询。

    因此,您要么在开始时执行此操作,然后使用方法链扩展“新”查询,要么在最后执行此操作,然后获取“新”查询。只要您在执行查询之前调用它就可以了。

    【讨论】:

    • 实际上在最后一种情况下确实如此 - 在ToList 之后调用AsNoTracking 可能会抛出。如果没有,它实际上将是一个空操作,因为在调用 AsNoTracking 时实体已经在内存中
    • @PanagiotisKanavos 是的,这就是为什么我说“在执行查询之前”。ToList() 执行查询。我现在用粗体表示
    • 链接失效了,假设是这个? docs.microsoft.com/en-us/dotnet/api/…
    • @PanagiotisKanavos 这不会是空操作。这将是一个编译时错误。你不能在 ToList 之后调用 AsNoTracking,因为你不再有一个 IQueryable 来调用它。
    • @AlexanderDerck 你的实现被颠倒了。 IQueryable 实现了 IEnumberable。
    【解决方案2】:

    我认为

    var matchingCustomers = context.Customers.Where(n => n.city == "Milan").Skip(50).Take(100).OrderBy(n => n.Name).ToList().AsNoTracking();
    

    很重要,因为一旦 EF 执行并跟踪了查询,您就试图将 NoTracking 应用于内存中的数据结构。

    当你使用这个流畅的 API 时;您正在定义一个查询而不执行它,当然,直到您执行查询。 ToList() 将执行查询并将数据带入内存以将其转换为 List<T> 数据结构。

    让我们拆分命令来理解这一点:

    • context.Customers --> 从客户中选择 [*]
    • Where(n => n.city == "Milan") --> 从客户所在城市中选择 [*] == '米兰'
    • Skip(50).Take(100) --> 从客户中选择 [*] where city == 'Milan' 偏移 50 行仅获取下 100 行
    • OrderBy name --> 从客户中选择 [*] where city == 'Milan' OFFSET 50 ROWS FETCH NEXT 100 ROWS ONLY ORDER by name
    • ToList() --> 执行查询,默认使用Tracking将数据带入内存!
    • AsNoTraking() --> 什么都不做,因为 EF 已经执行了查询 并跟踪数据。

    【讨论】:

    • 在回答问题之前,请先尝试做您要讨论的内容。你不能在 ToList 之后调用 AsNoTracking,因为你不再有一个 IQueryable 来调用它。它会给出一个编译时错误。
    • @Cdaragorn 然后像我说的那样有效地什么都不做。 ;)
    • 物理上不可能编译不是“什么都不做”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-28
    相关资源
    最近更新 更多