使用EF6语法在EF Core中加载相关实体

时间:2017-05-20 09:47:13

标签: c# entity-framework-core

在EF6中我们曾经加载过这样的相关实体:

query                                                   // (A)
  .Include(q => q.Employee.Supervisor.Office.Address)   
  .Include(q => q.Orders);

那会急切加载该链中的所有实体。

在EF Core中,您应该这样做:

query                                                   // (B)
  .Include(q => q.Employee)
    .ThenInclude(q => q.Supervisor)
      .ThenInclude(q => q.Office)
        .ThenInclude(q => q.Address)
  .Include(q => q.Orders);

这很多(很多!)不太友好,但有效。

我们的代码库有大量(A)次调用,我们必须将其升级到(B),以便我们可以使用EF Core。

我发现在许多情况下,EF Core与(A)完全正常,即使它不应该! ......有时它完全失败了。

这是侥幸吗?它是否应该在某些情况下与(A)一起使用?因为除非我必须这样做,否则我不想进行数百次更改,然后对其进行测试。

1 个答案:

答案 0 :(得分:3)

实际上,只要包含路径包含简单的引用类型(即非集合类型)导航属性,两种语法都可以在EF Core中使用。这是因为EF6和EF Core中的Include的“流畅”版本正在建模一种描述导航属性路径的类型安全方式,如Root - > Employee - > Supervisor - > Office - > Address,哪个不安全版本表示为string(EF6和EF Core也支持)"Employee.Supervisor.Office.Address"。 EF Core示例似乎更喜欢始终使用Include / ThenInclude模式,因为它更具通用性,适用于引用和集合类型属性,我们将在后面看到。

描述集合类型导航属性的相关属性时会产生真正的差异。假设您示例中的Order类具有导航属性ICollction<OrderDetail> OrderDetailsOrderDetail类包含Vendor Vendor属性。包含root + orders +订单详细信息+订单详细信息供应商的string导航路径为"Orders.OrderDetails.Vendor",但不能简单地表示为Include(q => q.Orders.OrderDetails.Vendor)表达式(编译错误)。 EF6和EF Core采用不同的方法。 EF6使用标准LINQ Select运算符解析它:

.Include(q => q.Orders.Select(o => o.OrderDetails.Select(d => d.Vendor)))

和EF Core - 使用ThenInclude自定义扩展方法:

.Include(q => q.Orders).ThenInclude(o => o.OrderDetails).ThenInclude(d => d.Vendor)

我不能说哪一个更好 - 两者都有利弊。 EF6生成嵌套,但允许外部代码提供包含表达式(形式为Expression<Func<T, object>>)而不引用EF相关程序集。另一方面,EF Core语法是“平坦的”,如果它们是集合或引用,则允许轻松链接附加属性,但是没有简单的方法来提供外部包含。

但重点是 - 无论好坏,包含集合元素相关属性的语法是不同的,并且在将EF6代码移植到EF Core时必须考虑。实际上在一些初始EF Core版本中支持旧语法(除了新语法之外),但由于某些未知原因,它已被删除。唯一的好处是你不需要修改所有你的Include - 只需找到使用Select的内容并将其转换为ThenInclude语法