ef-core 嵌套 table 聚合函数给出 "NavigationExpandingExpressionVisitor failed"
ef-core nested table aggregate functions give "NavigationExpandingExpressionVisitor failed"
我有一个嵌套数据模型,我想从中获取按顶级 属性 分组的聚合数据。
例如我的模型:
public class Scan {
public long Id {get; set;}
public int ProjectId { get; set; }
public int ScanUserId { get; set; }
public ICollection<ScanItem>? Items { get; set; }
}
public class ScanItem
{
public long Id { get; set; }
public long InventoryScanId { get; set; }
public double Qty { get; set; }
}
我想按 Scan.ScanUserId 对所有扫描进行分组,然后获取每个用户 ScanItems.Qty 的总和。我的查询看起来像这样,EF 给出了以下错误:
Processing of the LINQ expression 'AsQueryable((Unhandled
parameter: x).Items)' by 'NavigationExpandingExpressionVisitor' failed
from scan in Scans
.Include(x=>x.ScanUser)
.Include(x=>x.Items)
group scan by new { scan.ScanUser.Name, scan.ScanUser.Id } into g
select new
{
UserId = g.Key.Id,
Name = g.Key.Name,
LastSyncTime = g.Max(x => x.ScanDate),
ScanItems = g.Sum(x=>x.Items.Sum(i=>i.Qty))
}
我如何 运行 在嵌套 table 的属性上聚合函数而不在客户端对其进行评估?
EF Core 仍然无法翻译 GroupBy
结果(分组)上的嵌套聚合。
您必须使用GroupBy
(或查询语法group element by key
中的element
)的元素选择器预先计算嵌套聚合:
from scan in Scans
group new { scan.ScanDate, Qty = scan.Items.Sum(i => i.Qty) } // <--
by new { scan.ScanUser.Name, scan.ScanUser.Id } into g
select new
{
UserId = g.Key.Id,
Name = g.Key.Name,
LastSyncTime = g.Max(x => x.ScanDate),
ScanItems = g.Sum(x => x.Qty) // <--
}
**更新:**对于 SqlServer,上述 LINQ 查询转换为 SQL 查询,如下所示:
SELECT [s1].[Id] AS [UserId], [s1].[Name], MAX([s0].[ScanDate]) AS [LastSyncTime], SUM((
SELECT SUM([s].[Qty])
FROM [ScanItem] AS [s]
WHERE [s0].[Id] = [s].[InventoryScanId])) AS [ScanItems]
FROM [Scan] AS [s0]
INNER JOIN [ScanUser] AS [s1] ON [s0].[ScanUserId] = [s1].[Id]
GROUP BY [s1].[Name], [s1].[Id]
如评论中所述生成 SQL 执行异常 "Cannot perform an aggregate function on an expression containing an aggregate or a subquery.".
因此您确实需要另一种方法 - 在分组之前使用 left join
展平结果集,然后对该集执行分组/聚合:
from scan in Scans
from item in scan.Items.DefaultIfEmpty() // <-- left outer join
group new { scan, item } by new { scan.ScanUser.Name, scan.ScanUser.Id } into g
select new
{
UserId = g.Key.Id,
Name = g.Key.Name,
LastSyncTime = g.Max(x => x.scan.ScanDate),
ScanItems = g.Sum(x => (double?)x.item.Qty) ?? 0
};
现在转换为有效的 SqlServer SQL 查询:
SELECT [s1].[Id] AS [UserId], [s1].[Name], MAX([s].[ScanDate]) AS [LastSyncTime], COALESCE(SUM([s0].[Qty]), 0.0E0) AS [ScanItems]
FROM [Scan] AS [s]
LEFT JOIN [ScanItem] AS [s0] ON [s].[Id] = [s0].[InventoryScanId]
INNER JOIN [ScanUser] AS [s1] ON [s].[ScanUserId] = [s1].[Id]
GROUP BY [s1].[Name], [s1].[Id]
我有一个嵌套数据模型,我想从中获取按顶级 属性 分组的聚合数据。 例如我的模型:
public class Scan {
public long Id {get; set;}
public int ProjectId { get; set; }
public int ScanUserId { get; set; }
public ICollection<ScanItem>? Items { get; set; }
}
public class ScanItem
{
public long Id { get; set; }
public long InventoryScanId { get; set; }
public double Qty { get; set; }
}
我想按 Scan.ScanUserId 对所有扫描进行分组,然后获取每个用户 ScanItems.Qty 的总和。我的查询看起来像这样,EF 给出了以下错误:
Processing of the LINQ expression 'AsQueryable((Unhandled parameter: x).Items)' by 'NavigationExpandingExpressionVisitor' failed
from scan in Scans
.Include(x=>x.ScanUser)
.Include(x=>x.Items)
group scan by new { scan.ScanUser.Name, scan.ScanUser.Id } into g
select new
{
UserId = g.Key.Id,
Name = g.Key.Name,
LastSyncTime = g.Max(x => x.ScanDate),
ScanItems = g.Sum(x=>x.Items.Sum(i=>i.Qty))
}
我如何 运行 在嵌套 table 的属性上聚合函数而不在客户端对其进行评估?
EF Core 仍然无法翻译 GroupBy
结果(分组)上的嵌套聚合。
您必须使用GroupBy
(或查询语法group element by key
中的element
)的元素选择器预先计算嵌套聚合:
from scan in Scans
group new { scan.ScanDate, Qty = scan.Items.Sum(i => i.Qty) } // <--
by new { scan.ScanUser.Name, scan.ScanUser.Id } into g
select new
{
UserId = g.Key.Id,
Name = g.Key.Name,
LastSyncTime = g.Max(x => x.ScanDate),
ScanItems = g.Sum(x => x.Qty) // <--
}
**更新:**对于 SqlServer,上述 LINQ 查询转换为 SQL 查询,如下所示:
SELECT [s1].[Id] AS [UserId], [s1].[Name], MAX([s0].[ScanDate]) AS [LastSyncTime], SUM((
SELECT SUM([s].[Qty])
FROM [ScanItem] AS [s]
WHERE [s0].[Id] = [s].[InventoryScanId])) AS [ScanItems]
FROM [Scan] AS [s0]
INNER JOIN [ScanUser] AS [s1] ON [s0].[ScanUserId] = [s1].[Id]
GROUP BY [s1].[Name], [s1].[Id]
如评论中所述生成 SQL 执行异常 "Cannot perform an aggregate function on an expression containing an aggregate or a subquery.".
因此您确实需要另一种方法 - 在分组之前使用 left join
展平结果集,然后对该集执行分组/聚合:
from scan in Scans
from item in scan.Items.DefaultIfEmpty() // <-- left outer join
group new { scan, item } by new { scan.ScanUser.Name, scan.ScanUser.Id } into g
select new
{
UserId = g.Key.Id,
Name = g.Key.Name,
LastSyncTime = g.Max(x => x.scan.ScanDate),
ScanItems = g.Sum(x => (double?)x.item.Qty) ?? 0
};
现在转换为有效的 SqlServer SQL 查询:
SELECT [s1].[Id] AS [UserId], [s1].[Name], MAX([s].[ScanDate]) AS [LastSyncTime], COALESCE(SUM([s0].[Qty]), 0.0E0) AS [ScanItems]
FROM [Scan] AS [s]
LEFT JOIN [ScanItem] AS [s0] ON [s].[Id] = [s0].[InventoryScanId]
INNER JOIN [ScanUser] AS [s1] ON [s].[ScanUserId] = [s1].[Id]
GROUP BY [s1].[Name], [s1].[Id]