在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)
一起使用?因为除非我必须这样做,否则我不想进行数百次更改,然后对其进行测试。
答案 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> OrderDetails
和OrderDetail
类包含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
语法