“AsNoTracking()”有什么区别?(涉及IT技术)

333

我对.AsNoTracking()扩展方法有疑问,因为这一切都很新,也很令人困惑。

我正在为一个网站使用每个请求上下文。

我的许多实体不会改变,因此不需要被跟踪,但是我有以下场景,在这种情况下我不确定会发生什么,甚至是否在这种情况下有所区别。

以下示例是我目前正在进行的操作:

context.Set<User>().AsNoTracking()
// Step 1) Get user
context.Set<User>()
// Step 2) Update user

这与上面相同,但是从步骤1中删除了.AsNoTracking()

context.Set<User>();
// Step 1) Get user
context.Set<User>()
// Step 2) Update user

步骤1和2使用相同的上下文,但发生的时间不同。我无法确定是否有任何区别。由于步骤2是更新,我猜两者都将在任何情况下两次访问数据库。

有人能告诉我区别是什么吗?

6个回答

259

区别在于第一种情况下检索到的用户没有被上下文跟踪,因此当您要将用户保存回数据库时,必须将其附加并正确设置用户状态,以便EF知道它应更新现有用户而不是插入新用户。在第二种情况下,如果您使用相同的上下文实例加载和保存用户,则不需要执行此操作,因为跟踪机制会为您处理。


3
我们是否可以在选择查询中为匿名类获得与context.Users.Select(u=> new { Name = u.Name })相同的好处呢?谢谢。 - Dilhan Jayathilake
7
匿名类不代表实体本身,因此它们没有追踪。 - Ladislav Mrnka
1
由于EF6有时会在视图上错误地推断实体键,所以AsNoTracking()是否忽略键并因此成为手动修复键的替代方法(假设不需要键的其他好处)。 - crokusek
4
请注意,AsNoTracking 的最大影响是懒加载将无法工作。 - Douglas Gaskell
@LadislavMrnka并不完全正确。如果您的匿名类型包含可以被跟踪的实体实例,则EF将跟踪匿名类型中的实体。因此,AsNoTracking()也适用于匿名类型。 - Mick

241

请查看此页面 Entity Framework 和 AsNoTracking

AsNoTracking 的作用

Entity Framework 提供了一些性能调优选项,以帮助您优化应用程序的性能。其中一个调优选项是 .AsNoTracking()。这个优化选项允许你告诉Entity Framework不要跟踪查询结果。这意味着Entity Framework不会对查询返回的实体执行任何额外的处理或存储。但是,这也意味着你无法更新这些实体,除非重新将它们附加到跟踪图中。

使用 AsNoTracking 可以获得显著的性能提升


21
有时候看起来收益可能会被抵消:https://dev59.com/fWox5IYBdhLWcg3wWjHQ - Fabrice
6
使用一步加载包含父子关系的复杂查询,我的性能提升了约50%。 - Karl
2
2022年的另一个反馈:使用AsNoTracking()(Entity Framework 6)获得了巨大的收益。实际上,由于其他原因 - 不在此处公开细节,但与EF的Include()方法有关 - 我已禁用跟踪,而不是对于我正在执行的特定linq查询使用AsNoTracking()的DbContext:ctx.Configuration.AutoDetectChangesEnabled = false;)。我会说性能提升至少95%,可能更多(我没有高估:执行时间从1小时以上降至不到15秒...) - ggo

75

禁用实体框架的跟踪功能

当您的查询用于读取操作时,推荐使用AsNoTracking()。在这些情况下,您会返回实体对象,但它们不受上下文的跟踪。这可以确保最小内存使用和最佳性能。

优点

  1. 比常规LINQ查询更快速。
  2. 完全实现对象。
  3. 简单易写,语法内置于编程语言中。

缺点

  1. 不适用于 CUD 操作。
  2. 某些技术限制,例如:对于 OUTER JOIN 查询使用 DefaultIfEmpty 的模式比 Entity SQL 中简单的 OUTER JOIN 语句产生更复杂的查询。
  3. 仍然不能使用LIKE进行通配符匹配。

更多信息请参考:

Entity Framework 性能考虑因素

Entity Framework 和 NoTracking


1
你仍然不能在一般模式匹配中使用LIKE。我找不到任何官方参考资料,但它似乎对我来说运行良好。 - kofifus

46

23

AsNoTracking()允许绕过EF中的“每个记录唯一键”要求(其他答案未明确提到)。

这在读取不支持唯一键的视图时非常有用,因为某些字段可能为空或视图的性质无法逻辑上建立索引。

对于这些情况,“键”可以设置为任何非空列,但是每次查询都必须使用AsNoTracking(),否则记录(按键重复)将被跳过。


6
强调一下在Views中的重要性,我有一个从View查询的查询语句,在通过SQL Server Management Studio(SSMS)运行时返回7条唯一记录。当通过EF运行时,如果没有使用AsNoTracking修饰符,则会得到第一条记录、第二条记录的三个副本和第三条记录的三个副本。这需要很多难以置信的思考来解决,而使用AsNoTracking就可以解决它! - Ade
当我使用Linq to Entities查询没有主键的视图时,我遇到了完全相同的问题。在经过半天的苦思冥想后,我才发现了AsNoTracking。这篇ASP.Net论坛帖子最终引导了我找到了它。 https://forums.asp.net/t/1864180.aspx?EF+returning+two+identical+records+when+2+different+records+are+in+the+table+ - red_dorian

16

如果您有其他东西改变了数据库(比如另一个进程),并且需要确保您可以看到这些更改,请使用AsNoTracking(),否则EF可能会给您上下文中最后一份副本,因此通常最好在每个查询中使用新的上下文:

http://codethug.com/2016/02/19/Entity-Framework-Cache-Busting/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接