【问题标题】:AsNoTracking() and IncludeAsNoTracking() 和包含
【发布时间】:2025-12-04 02:45:01
【问题描述】:

我有一个获取实体及其一些导航属性的 Linq 查询。

context.MyEntity
    .AsNoTracking()
    .Include(i=> i.Nav1)
    .Include(i=> i.Nav2)
    .Where(x=> x.Prop1==1)
    .FirstOrDefault();

我的问题是:

上述查询是否足以不跟踪MyEntity 或导航属性NAv1& Nav2 或者我必须为每个导航属性添加AsNoTracking

像这样:

context.MyEntity
    .AsNoTracking()
    .Include(i=> i.Nav1)
    .AsNoTracking()
    .Include(i=> i.Nav2)
    .AsNoTracking()
    .Where(x=> x.Prop1==1)
    .FirstOrDefault();

【问题讨论】:

  • 每个查询只需要AsNoTracking 一次,因此您的第一个示例是正确的。我相信第二个会抛出运行时异常(不确定是哪一个)。
  • 如果您链接多个 LINQ 方法,您总是将返回的序列从前一个方法传递到下一个方法。所以在AsNoTracking 之后你有一个查询,返回的实体不会被缓存
  • 感谢您的帮助
  • 以上两个cmets都是错误

标签: c# entity-framework linq


【解决方案1】:

在完成所有查询参数之后、将数据移入内存之前使用 AsNoTracking。在本例中,您需要:

context.MyEntity
    .Include(i=> i.Nav1)
    .Include(i=> i.Nav2)
    .Where(x=> x.Prop1==1)
    .AsNoTracking()
    .FirstOrDefault();

不会跟踪父实体的任何子对象。

【讨论】:

  • 在 .net core 中,考虑使用 context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; 来禁用跟踪行为作为配置而不是查询的属性。
  • 危险推荐。由于默认情况下启用更改跟踪,因此集中禁用此功能可能会使整个团队感到沮丧,而他们却没有意识到是什么影响了他们的工作。还很自然地假设当您对对象状态进行更改时,它们会在保存时保持不变。全局禁用可能会导致创建意外的孤立记录,这是一个可能会影响生产并且直到为时已晚才被发现的问题。更改跟踪是默认设置是有原因的。
  • @hunter 警告做得很好,但肯定有适当的时间使用它,例如长只读操作或只读应用程序。代码与意图匹配很重要。
  • @Daniel 请注意,目前在某些情况下.AsNoTracking() 会比.AsTracking() 慢。 github.com/aspnet/EntityFrameworkCore/issues/14366
  • @BenjaminBrandt 在发表此评论时,我的回答根本不适用于 EF Core。