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