entity framework4.1虚拟属性
如果我已经在我的模型中声明实体关系为虚拟的那么没有必要在我的LINQ查询中使用Include
语句,对吗?
例如:这是我的模特class:
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);
我将在访问时自动获得相关的实体。
我的理解是否正确?
另外,请告诉我在什么情况下,我应该更喜欢一个?
你是对的,但是这个规则更加复杂,使它真正按预期工作。 如果您定义导航属性, virtual
EF将在运行时创build一个从您的Brand
类派生出来的新类(dynamic代理),然后使用它。 这个新的dynamic创build的类包含第一次访问时加载导航属性的逻辑。 这个特性被称为延迟加载(或更好的透明延迟加载)。
做这个工作必须遵守什么规则:
- 类中的所有导航属性都必须是
virtual
- dynamic代理创build不能被禁用(
context.Configuration.ProxyCreationEnabled
)。 它是默认启用的。 - 延迟加载不能被禁用(
context.Configuration.LazyLoadingEnabled
)。 它是默认启用的。 - 必须连接实体(如果从数据库装载实体,则默认为上下文)上下文不得处理=延迟加载只能在用于从数据库加载的生存上下文范围内(或者代理实体已连接)
延迟加载的对面称为加载,这就是Include
所做的事情。 如果使用Include
导航属性与主实体一起加载。
延迟加载和预先加载的使用取决于您的需求和性能。 Include
将所有数据加载到单个数据库查询中,但是在使用大量包含或加载大量实体时,可能会导致巨大的数据集 。 如果您确定需要Brand
和所有Products
进行加工,则应使用急切加载。
如果您不确定您将需要哪个导航属性,则会使用延迟加载。 例如,如果您加载了100个品牌,但只需要访问某个品牌的产品,则无需在初始查询中加载所有品牌的产品。 延迟加载的缺点是每个导航属性的单独查询(数据库往返)=>如果你加载100个品牌没有包含,你将访问每个Brand
实例中的Products
属性,你的代码将生成另外100个查询来填充这些导航属性=渴望加载将使用单一的查询,但延迟加载使用101查询(这被称为N + 1问题)。
在更复杂的情况下,您可以发现这两种策略都不需要,您可以使用第三种策略,即显式加载或单独查询加载品牌,而不是所有品牌的产品。
显式加载与延迟加载具有相似的缺点,但您必须手动触发它:
context.Entry(brand).Collection(b => b.Products).Load();
显式加载的主要优点是能够过滤关系。 您可以在Load()
Query()
之前使用Query()
,并使用任何过滤或嵌套关系的加载。