如果我已将模型中的实体关系声明为虚拟关系,则无需在 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);
并且在访问时我将自动获得可用的相关实体。
我的理解正确吗?
另外,请告诉我在什么情况下我应该选择其中一种而不是另一种?
最佳答案
你是对的,但规则要更复杂才能使其真正按预期工作。如果您定义导航属性 virtual
EF 将在运行时创建一个从您的 Brand
派生的新类(动态代理)类并使用它来代替。这个新的动态创建的类包含首次访问时加载导航属性的逻辑。此功能称为延迟加载(或更好的透明延迟加载)。
要使这项工作成功,必须满足哪些规则:
- 类中的所有导航属性必须为
virtual
- 不得禁用动态代理创建 (
context.Configuration.ProxyCreationEnabled
)。默认情况下启用。 - 不得禁用延迟加载 (
context.Configuration.LazyLoadingEnabled
)。默认情况下启用。 - 实体必须附加(如果从数据库加载实体则默认)到上下文,并且上下文不得被释放 = 延迟加载仅在用于从数据库加载实体的事件上下文范围内(或附加代理实体的位置)里>
延迟加载的反面称为急切加载,这就是 Include
做。如果您使用Include
您的导航属性与主实体一起加载。
延迟加载和预先加载的使用取决于您的需求以及性能。 Include
在单个数据库查询中加载所有数据,但可能会导致 huge data set当使用大量包含或加载大量实体时。如果您确定需要Brand
以及所有Products
为了进行处理,您应该使用预先加载。
如果您不确定需要哪个导航属性,则会依次使用延迟加载。例如,如果您加载 100 个品牌,但您只需要访问一个品牌的产品,则无需在初始查询中加载所有品牌的产品。延迟加载的缺点是每个导航属性的单独查询(数据库往返)=>如果您加载 100 个品牌而不包含,您将访问 Products
每个属性Brand
例如,您的代码将生成另外 100 个查询来填充这些导航属性 = 急切加载将仅使用单个查询,但延迟加载使用 101 个查询(称为 N + 1 问题)。
在更复杂的场景中,您会发现这些策略都无法满足您的需要,您可以使用称为显式加载的第三种策略或单独的查询来加载品牌以及您需要的所有品牌的产品。
显式加载与延迟加载有类似的缺点,但您必须手动触发它:
context.Entry(brand).Collection(b => b.Products).Load();
显式加载的主要优点是能够过滤关系。您可以使用Query()
之前Load()
并使用嵌套关系的任何过滤甚至预先加载。
关于entity-framework-4.1 - Entity Framework 4.1 虚拟属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7738722/