实体框架 5 预先加载父属性

本文关键字:加载 属性 框架 实体 | 更新日期: 2023-09-27 18:32:59

我对某个父实体(Order(有一个查询,我想急切地加载它的一些子集合或属性。我有一个这样的查询:

public void QueryMethod()
{
    using (var context = new MyContext())
    {
        var orders = context.Order.Include("OrderProduct")
                                  .Include("OrderProduct.ProductVariant")
                                  .Where(some query)
                                  .ToList();
    }
}

正在做的是循环浏览这个订单集合,对于我到达的每个Order OrderProductProductVariant属性。当上下文处于活动状态时,我可以在查询方法中执行此操作。但是当我尝试在上下文之外访问ProductVariant.OrderProduct时,我ObjectDisposedException.

顺便说一句,出于某种奇怪的原因,我正在尝试访问ProductVariant.OrderProduct。我想我不应该像这样访问它,但我的观点是我可以从OrderProduct到达ProductVariant,但我不能从ProductVariant访问到OrderProduct。我想知道为什么我会收到此错误,尽管我在急切的加载属性中添加了OrderProduct.ProductVariant。它不应该双向工作吗?

任何帮助将不胜感激。

实体框架 5 预先加载父属性

在上下文之外获得ObjectDisposedException的事实表明实体框架尝试通过从数据库延迟加载来加载ProductVariant.OrderProduct引用的对象。

现在,这并不一定意味着 - 这个陈述听起来很奇怪 - ProductVariant.OrderProduct尚未加载并填充正确的实体。可能是这样,因为它只是您通过预先加载加载OrderProduct.ProductVariant的反属性。对于一对一和一对多关系,EF 将在加载导航属性时自动填充反向导航属性("关系修复"(。

尽管填充了反向导航属性,但它不一定标记为加载,这是由每个导航属性的上下文维护的标志,该标志告知 EF 在代码中访问导航属性时是否必须通过延迟加载从数据库加载导航属性。

例如,对于一对多关系,很容易看出,EF 在由于关系修复而填充导航属性时,不得将导航属性标记为已加载。例如:如果您加载的订单包括其客户参考 - context.Orders.Include("Customer").Single... - 则急切加载的客户中的Orders集合将包含此加载的订单(由于关系修复(。但是,此单个订单很可能不是此客户拥有的唯一订单(或者至少 EF 无法知道这是唯一的订单还是数据库中是否有更多订单(。如果访问 Customer.Orders 集合,您通常期望不仅返回此单个订单,而且返回客户的所有订单 - 换句话说,您期望发生延迟加载查询,从数据库加载客户的其余订单。

现在,对于

一对一的关系,这个论点并不真正令人信服,因为对于这样的关系,很明显数据库中不能有多个相关对象。那么,如果已加载此单个相关对象,EF 为什么要运行延迟加载查询?

我不知道为什么EF仍然尝试为一对一关系加载反向导航属性,但在这方面它可能只是没有区分一对多和一对一关系。也许 EF 遵循一般规则,即如果关系的主方由关系修复填充,则不会将其标记为已加载,并且在任何情况下访问它时都会发生延迟加载。(我无法从您的代码片段中看到OrderProductProductVariant是主体,这只是一个猜测。

无论如何,在您的情况下,我会禁用延迟加载甚至代理创建(包括禁用延迟加载(,因为您在using块中使用Include并且延迟加载在这里没有任何好处。您遇到的异常应该会消失:

using (var context = new MyContext())
{
    context.Configuration.ProxyCreationEnabled = false;
    var orders = context.Order.Include("OrderProduct")
                              .Include("OrderProduct.ProductVariant")
                              .Where(some query)
                              .ToList();
}