EF Core,投影子 collection 预加载
EF Core, projection sub collection eager loading
在 EF 核心中,我试图用子 collection 投影出一个结果集。
ctx.As.Select(a => new
{
AId = a.Id,
BNames = a.Bs.Select(x=>x.Name) //SubCollection
})
然而,当执行此操作时,BNames collection 是惰性的,因此当它被枚举时,它会为每一行触发一个单独的查询。例如,对于 B 的 collection.
中的 2 个项目
[a].[Id] AS [AId] FROM [As] AS [a]
p_executesql N'SELECT [x].[Name]
FROM [Bs] AS [x]
WHERE @_outer_Id = [x].[AId]',N'@_outer_Id int',@_outer_Id=1
p_executesql N'SELECT [x].[Name]
FROM [Bs] AS [x]
WHERE @_outer_Id = [x].[AId]',N'@_outer_Id int',@_outer_Id=2
在 EF6 中,相同的查询结果如下(如我所料):
SELECT
[Extent1].[Id] AS [Id],
[Project1].[C1] AS [C1],
[Project1].[Name] AS [Name]
FROM [dbo].[A] AS [Extent1]
LEFT OUTER JOIN (SELECT
[Extent2].[Name] AS [Name],
[Extent2].[A_Id] AS [A_Id],
1 AS [C1]
FROM [dbo].[B] AS [Extent2] ) AS [Project1] ON [Extent1].[Id] = [Project1].[A_Id]
ORDER BY [Extent1].[Id] ASC, [Project1].[C1] ASC
如何让 EF 预先加载子collection BNames
?
注意: 这与包含具有 .Include
的子实体不同,因为这是自定义投影,而不是导航 属性。此处使用 .Include
会导致错误。
这里有完整的回购代码:https://gist.github.com/lukemcgregor/692834629da09b21d5a35515e86c9002
这在 EF Core 2.1 中使用其相关子查询优化是可能的。
您需要更新到 EF Core 2.1 并通过向子查询添加 .ToList()
来进行小的修改以选择优化:
foreach (var thing in ctx.As
.Select(a => new
{
AId = a.Id,
BNames = a.Bs.Select(x => x.Name).ToList()
}))
参见Optimization of correlated subqueries in New features in EF Core 2.1。
在 EF 核心中,我试图用子 collection 投影出一个结果集。
ctx.As.Select(a => new
{
AId = a.Id,
BNames = a.Bs.Select(x=>x.Name) //SubCollection
})
然而,当执行此操作时,BNames collection 是惰性的,因此当它被枚举时,它会为每一行触发一个单独的查询。例如,对于 B 的 collection.
中的 2 个项目[a].[Id] AS [AId] FROM [As] AS [a]
p_executesql N'SELECT [x].[Name]
FROM [Bs] AS [x]
WHERE @_outer_Id = [x].[AId]',N'@_outer_Id int',@_outer_Id=1
p_executesql N'SELECT [x].[Name]
FROM [Bs] AS [x]
WHERE @_outer_Id = [x].[AId]',N'@_outer_Id int',@_outer_Id=2
在 EF6 中,相同的查询结果如下(如我所料):
SELECT
[Extent1].[Id] AS [Id],
[Project1].[C1] AS [C1],
[Project1].[Name] AS [Name]
FROM [dbo].[A] AS [Extent1]
LEFT OUTER JOIN (SELECT
[Extent2].[Name] AS [Name],
[Extent2].[A_Id] AS [A_Id],
1 AS [C1]
FROM [dbo].[B] AS [Extent2] ) AS [Project1] ON [Extent1].[Id] = [Project1].[A_Id]
ORDER BY [Extent1].[Id] ASC, [Project1].[C1] ASC
如何让 EF 预先加载子collection BNames
?
注意: 这与包含具有 .Include
的子实体不同,因为这是自定义投影,而不是导航 属性。此处使用 .Include
会导致错误。
这里有完整的回购代码:https://gist.github.com/lukemcgregor/692834629da09b21d5a35515e86c9002
这在 EF Core 2.1 中使用其相关子查询优化是可能的。
您需要更新到 EF Core 2.1 并通过向子查询添加 .ToList()
来进行小的修改以选择优化:
foreach (var thing in ctx.As
.Select(a => new
{
AId = a.Id,
BNames = a.Bs.Select(x => x.Name).ToList()
}))
参见Optimization of correlated subqueries in New features in EF Core 2.1。