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