获取具有AsNoTracking()的实体是否禁用对DetectChanges()的自动调用?

时间:2014-01-08 06:41:52

标签: entity-framework ef-code-first query-performance

我最近才了解AsNoTracking()DetectChanges()AutoDetectChangesEnabled这个概念。我理解当通过使用AsNoTracking()的实体框架从数据库中获取记录时,实体框架不会跟踪这些记录的任何更改,并且在这种情况下更新所获取记录的任何属性都将失败。

我的问题是,如果以这种方式提取记录,是否还会导致禁用对DetectChanges()的自动调用,或者是否必须通过设置显式完成:

Context.Configuration.AutoDetectChangesEnabled = false;

另外请告诉我,如果在严格获取数据的同时执行这两项操作时,它会产生什么影响(在性能方面):

Context.Configuration.AutoDetectChangesEnabled = false;
Context.Set<T>().AsNoTracking();

2 个答案:

答案 0 :(得分:29)

  

它还会导致禁用自动调用DetectChanges()

不,不会。但是你必须意识到AsNoTrackingDetectChanges彼此无关(除了成为EF的一部分)。无论是否启用AutoDetectChanges,使用AsNoTracking获取的对象都不会被检测到。此外,AsNoTracking适用于上下文级别的DbSet级别AutoDetectChangesEnabled。让DbSet方法影响整个上下文会很糟糕。

  

或[设置AutoDetectChangesEnabled]必须明确地完成

好吧,你可能不应该禁用AutoDetectChanges。 如果你这样做,你必须知道你做了什么。

  

如果执行了两个操作,它会产生什么影响(就性能而言)

如上所述,他们没有关系。它们都可以以自己的方式提高性能。

    如果您想获取只读数据,
  • AsNoTracking非常棒。它没有副作用(如:效果很明显)
  • 设置AutoDetectChangesEnabled = false会停止DetectChanges的自动调用(可能很多),但它有副作用需要注意。来自Lerman&amp;米勒的书 DbContext

      

    需要调用DetectChanges时的工作并不像它那样简单   可能会出现。实体框架团队强烈建议您   如果您遇到,只能交换到手动调用DetectChanges   性能问题。它也建议只选择退出自动   检测代码表现不佳的部分并重新启用它   一旦有关部分完成执行。

答案 1 :(得分:20)

我们发现设置AutoDetectChangesEnabled = false可能会产生大量(即10倍)性能影响。

背景:我们的系统完全由使用变更检测代理的EF模型对象组成。也就是说,我们所有的DB字段和关系属性都被声明为虚拟。我们还有一个相对深度结构化的对象模型。即对象A包含一组对象B,其又包含一组对象C等。我们已经观察到通过EF / LINQ查询实例化这些对象的非平凡(> 100)数量是昂贵的。例如,在一种情况下,实例化250个对象需要大约2秒。我们还观察到实例化相同的结构,但使用匿名对象需要大约25毫秒。最后,我们观察到如果我们设置AutoDetectChangesEnabled = false,我们可以使用查询实例化EF模型对象并再次实现约25毫秒。

所以,至少对我们来说,通过设置它是错误的,可以获得巨大的收益。我们使用工作单元模式,并明确指出工作单元是否为只读。对于只读工作单元,设置AutoDetectChangesEnabled = false非常安全,因为永远不会有任何更改。实际上,我们在初始发布两年后将这一更改添加到我们的系统中(因此代码中有许多预先存在的工作单元)并且更改没有破坏任何内容,并且显着提高了性能。

我们还尝试了AsNoTracking(),发现它基本上没有给我们带来性能提升。据我了解,使用AsNoTracking()的查询意味着对象不会被放入身份映射中,如果在上下文中多次引用该对象,这将强制EF从磁盘重新获取该对象(例如,在不同的查询中)。因此AsNoTracking()有一些潜在的缺点。

实施细则

  • 我们有一个DBContext的子类,它为我们的工作单元提供了很多基础设施
  • 我们的工作单位基本上是围绕上下文的轻量级包装
  • 当分配工作单元时(通常在使用块中),它通过注入接收这些上下文之一(我们使用Castle / Windsor)
  • 在初始化期间,工作单元调用将AutoDetectChangesEnabled设置为false的上下文的方法
  • 目前,我们所有的时间都是这样做的,因为我们总是使用变更检测代理并且它们不需要AutoDetectChangesEnabled
  • 以前我们只为“只读”工作单元做过,因为如果在UoW中没有修改任何内容就不需要检测更改(当我们分配一个工作单元时,我们明确指出它是否为只读或不)
  •   -