如果您谈论EF中的动态代理,则有两种不同的类型可以区分:
通常,变更跟踪代理还可以充当延迟加载的代理。反之则不成立。这是因为对变更跟踪代理的要求更高,尤其是所有属性(标量属性)也必须为virtual
。对于延迟加载,导航属性为就足够了virtual
。
更改跟踪代理始终还可以利用延迟加载这一事实是DbContext具有此配置标志的主要原因:
DbContext.Configuration.LazyLoadingEnabled
默认情况下,此标志为true。将其设置为false
禁用延迟加载,即使创建了代理也是如此。如果您正在使用变更跟踪代理,但又不想将这些代理用于延迟加载,则这一点尤其重要。
选项 ...
DbContext.Configuration.ProxyCreationEnabled
...完全禁用代理创建-以及更改跟踪和延迟加载。
仅当您的实体类满足创建更改跟踪或延迟加载代理的要求时,这两个标志才完全有意义。
现在,您知道了动态延迟加载代理的目的。那么,为什么要使用动态变更跟踪代理呢?
实际上,我知道的唯一原因是性能。但这是一个非常有力的理由。将基于快照的更改跟踪与基于代理的更改跟踪进行比较,性能差异是巨大的-从我的测量中可以得出50到100的因子是现实的(取材于一种方法,该方法需要大约一小时的10000个实体,并且具有基于快照的更改跟踪和30至60秒将所有属性设为虚拟以启用更改跟踪代理后)。如果您有一些应用程序可以处理和更改许多(例如超过1000个)实体,那么这将成为一个重要因素。在Web应用程序中,您可能只对Web请求中的单个实体执行“创建/更改/删除”操作,此区别无关紧要。
在几乎所有情况下,如果您不想使用延迟加载代理,都可以利用紧急加载或显式加载来实现相同的目标。基于代理的延迟加载或基于非代理的显式加载的性能是相同的,因为加载导航属性时会发生基本上相同的查询-第一种情况是代理执行查询,第二种情况是您的手写代码。因此,您可以活着而无需延迟加载代理,而不会损失太多。
但是,如果您想要合理的性能来处理很多很多实体,除了使用EntityObject
EF 4.0中的派生实体(不是EF 4.1中的一个选项,因为使用时禁止使用DbContext
)或完全不使用Entity Framework,没有其他方法可以替代更改跟踪代理。
编辑(2012年5月)
同时,我了解到在某些情况下,与基于快照的跟踪相比,更改跟踪代理的性能不会更快甚至更差。
由于使用更改跟踪代理时存在这些复杂性,因此首选方法是默认使用基于快照的更改跟踪,并且仅在要求高性能且事实证明它们比基于快照快的情况下,谨慎使用代理(在进行一些测试之后)变更追踪。