Entity Framework 4.1 虚拟属性

54
如果我在我的模型中将实体关系声明为虚拟的,那么在我的LINQ查询中就不需要使用Include语句,对吗?例如:这是我的模型类:
public class Brand
{
    public int BrandID { get; set; }
    public string BrandName { get; set; }
    public string BrandDesc { get; set; }
    public string BrandUrl { get; set; }

    public virtual ICollection<Product> Products { get; set; }
}

对于上面的模型类,我不需要使用var brandsAndProduct = pe.Brands.Include("Products").Single(brand => brand.BrandID == 22);

相反,我只需使用简单的var brandsAndProduct = pe.Brands.Where(brand => brand.BrandID == 22);,当访问时会自动提供相关实体。

我的理解正确吗?

另外,请告诉我何时应该更喜欢其中之一?

1个回答

168
您是正确的,但为了使规则真正起作用,它更加复杂。如果您将导航属性定义为virtual,EF将在运行时创建一个新类(动态代理),该类派生自您的Brand类并使用它。这个新创建的动态类包含逻辑,可以在第一次访问时加载导航属性。这个功能称为延迟加载(或更好的透明延迟加载)。
要使其起作用,必须满足以下规则:
  • 类中的所有导航属性都必须是virtual
  • 不能禁用动态代理创建(context.Configuration.ProxyCreationEnabled)。默认情况下启用。
  • 不能禁用延迟加载(context.Configuration.LazyLoadingEnabled)。默认情况下启用。
  • 实体必须被附加(如果您从数据库加载实体,则默认情况下)。到上下文和上下文必须未释放=延迟加载仅在用于从数据库加载它(或连接代理实体的)存活上下文范围内工作。
延迟加载的相反是急切加载,这就是Include所做的。如果您使用Include,则会与主实体一起加载导航属性。
懒加载和贪婪加载的使用取决于你的需求和性能。 Include 通过单个数据库查询加载所有数据,但在使用大量包含或加载大量实体时可能会导致大数据集。如果您确定需要处理Brand和所有Products,则应使用贪婪加载。
反之,如果您不确定需要哪个导航属性,则可以使用延迟加载。例如,如果您加载了100个品牌,但只需要访问一个品牌的产品,则不需要在初始查询中为所有品牌加载产品。延迟加载的缺点是每个导航属性都需要单独的查询(数据库往返)=>如果您没有包含并且要在每个Brand实例中访问Products属性,则您的代码将生成另外100个查询以填充这些导航属性=贪婪加载仅使用单个查询,但延迟加载使用101个查询(称为N + 1问题)。
在更复杂的情况下,您可能会发现这些策略都无法满足您的需求,您可以使用第三种策略,即显式加载或分别查询以加载您需要的所有品牌和产品。
显式加载有与延迟加载类似的缺点,但必须手动触发:
context.Entry(brand).Collection(b => b.Products).Load();

明确加载的主要优点在于能够过滤关系。您可以在调用Load()之前使用Query(),并使用任何过滤甚至是嵌套关系的急切加载。

3
我觉得这个答案简明扼要并且完整,谢谢。提及“加载相关数据”(Loading Related Data)的文章链接为:http://msdn.microsoft.com/en-us/magazine/hh205756.aspx。 - LCJ
谢谢您的回答。即使到了2016年,它仍然对我有帮助。我还有一个问题:是否有一种方法可以始终在一次调用中急切地加载每个属性?因为有些情况下需要加载多个导航属性的模型需要每次都加载。 - anuith

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接