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