【问题标题】:Entity Framework - Eager loading related entities实体框架 - 急切加载相关实体
【发布时间】:2011-04-09 22:18:12
【问题描述】:

我正在使用带有 MVC 的 Entity Framework 4,并且需要确保在控制器方法返回之前我想在视图中使用的任何引用实体都已加载,否则视图会吐出可怕的东西:

ObjectContext 实例已被释放,不能再用于需要连接的操作。

当直接从上下文中选择时,我可以只使用Include(string) 方法来强制它们包含在生成的 SQL 查询中:

var sellers = context.Sellers.Include("Recommendations.User").ToList();

但是,如果我有(例如)一个接受实体并需要加载所有项目的辅助方法,则没有可用的 Include 方法。

void Test(Seller seller)
{
    // ensure all recommendations and their users are loaded
}

蛮力方法是遍历它们:

foreach (var recommendation in seller.Recommendations)
    recommendation.User.ToString(); // just force a load

如果我有 100 条建议,这将在幕后创建 101 个 SQL 查询。理想情况下,我想要一种方法/方法,只需一次访问 SQL 即可加载所有 RecommendationUser 对象。

给我钱。

编辑我并没有兴趣讨论这是一个好还是坏的架构。为了这个问题,我已经简化了我的场景。你能用 EF API 完成我的要求吗?

编辑 2

Ladislav's edit 提供了一种新方法的希望,但似乎我还没有做到。

我可以通过这个实现我想要的:

context.Sellers.Include("Recommendations.User").Single(s => s.Id == seller.Id);

这种方法不适用于LoadProperty...

context.LoadProperty(seller, "Recommendations.User");

...因为它失败并出现错误...

找不到指定的导航属性 Recommendations.User。

如果您没有对上下文的引用,这些方法都不起作用。

【问题讨论】:

  • 虽然这不能回答您的问题(因此我将其作为评论发布) - 它确实讨论了加载相关实体,因为它目前在 EF6 中工作。这也是谷歌搜索“实体框架加载相关实体”时出现的第一个 SOF 链接:msdn.microsoft.com/en-us/data/jj574232。所以我想我会分享...

标签: .net entity-framework entity-framework-4 eager-loading


【解决方案1】:

这是一个老问题,但在 EF6 中,您可以在 this 这样的实体上完成加载依赖对象:

context.Entry(seller).Collection(s => s.Recommendations).Query().Include(r => r.User)).Load();

这将为给定的seller 加载所有Recommendations 及其相关的Users

【讨论】:

    【解决方案2】:

    我认为这是您的存储库的一项工作,在您的情况下,它应该公开 GetFullSeller(由 Include 加载的所有属性)和 GetSeller(仅基本实体)等方法。

    编辑:

    在 EF v4 中有多种加载导航属性的方法。

    没有自动加载。

    【讨论】:

    • 这是否意味着您只会处理直接来自存储库的对象?如果您通过 WCF 收到一个实体,然后想要附加它并在其上填充更多字段,以便在最终保存之前进行更多转换,该怎么办?无论如何,我并不认为这是一个架构问题。我只想知道 API 是否支持这个,如果不支持,为什么不支持。
    【解决方案3】:

    我也有同样的情况。我觉得用EF很容易陷入101查询问题。

    一种解决方案可以是创建您的 Seller 类(由 EF 生成)的部分类,并实现一个返回 IQueryable 的 GetSubclassNameQ 和一个返回 IQueryable 的 GetSubclassNameQFull。

    public partial class Seller{
    
      public IQueryable<Recommendation> GetRecommendationsQ(EntityContainer entitycontainer) {
        return entitycontainer.Recommendations;
      }      
    
      public IQueryable<Recommendation> GetRecommendationsQFull(EntityContainer entitycontainer) {
        return this.GetRecommendationsQ(entitycontainer).Include("Recommendations.User");
      }
    
      public IQueryable<Recommendation> GetRecommendationsQ() {
        return GetRecommendationsQ(new EntityContainer());
      }
    
      public IQueryable<Recommendation> GetRecommendationsQFull() {
        return this.GetRecommendationsQ().Include("Recommendations.User");
      }
    
    }
    

    【讨论】:

      【解决方案4】:

      与其将实际的域对象 (EntityObjects) 传递给视图,不如使用控制器将它们映射到模型对象中,以便更好地表示视图实际应该显示的内容。这将减少视图中所需的逻辑量,并具有避免在上下文过期后传递 EntityObjects 的令人愉快的副作用。

      编辑基于您的编辑:

      不,API 没有办法获取单个实体对象并使其类型的所有其他实体对象在加载的同时被延迟填充特定属性。您最好首先使用Include 提及您在问题中显示的所有项目。

      【讨论】:

      • 感谢您的回答。为了清楚起见,我已经简化了我的案例。我确实使用了“视图模型”,因此我的视图中几乎没有任何逻辑。我的模型与关系密切相关,我不想在视图模型中重新创建该层次结构,因此我有一个基础级视图模型,其中包含一些实体枚举。就我而言,我需要在枚举中取消引用另一个实体。这不是一个真正的架构问题,更像是一个 API 问题。
      • 基于您的编辑 ;) 这不是我想要做的。我有卖家。我需要加载所有卖家的建议。对于这些建议中的每一个,我都需要加载相应的用户。我不需要加载任何其他卖家。
      • 如果我可以发明 API,我会说 seller.Load("Recommendations.User"),就像我在原始实体集查询中所做的一样(如在 OP 中)。
      • 我现在明白你的意思了。这可能非常方便。不幸的是,“包含”功能本质上与 ObjectQuery&lt;T&gt; 对象 (context.Sellers) 相关联,并且没有 API 允许您在 EntityCollection&lt;T&gt; 对象 (seller.Recommendations) 上要求的内容。跨度>
      猜你喜欢
      • 1970-01-01
      • 2012-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-23
      • 2012-09-10
      • 1970-01-01
      • 2011-05-03
      相关资源
      最近更新 更多