EF Core 3.0 SumAsync 触发聚合函数异常
EF Core 3.0 SumAsync triggers aggregate function exception
我正在升级到 EF Core 3.0 和 .NET Core 3.0,但我的一些查询停止工作。这是一个例子:
我有一个名为 Bins
的 table,我有另一个名为 BinItems
的 table,现在它当然是一对多关系。 BinItems
有一个名为 Qty
的 属性,我想根据客户在过滤器中给出的条件总结 BinItems
中的所有 Qty
。
代码如下:
var query = _binRepository.Table;
if (filter.LastRecountDate != null) {
query = query.Where(x => x.LastRecountDate.Date == filter.LastRecountDate.Value.Date);
}
if (filter.StartRecountDate != null) {
query = query.Where(x => x.LastRecountDate.Date >= filter.StartRecountDate.Value.Date);
}
if (filter.EndRecountDate != null) {
query = query.Where(x => x.LastRecountDate.Date <= filter.EndRecountDate.Value.Date);
}
if (filter.Active != null) {
query = query.Where(x => x.Active == filter.Active);
}
if (!string.IsNullOrEmpty(filter.BinLocation)) {
query = query.Where(x => x.BinLocation == filter.BinLocation);
}
if (!string.IsNullOrEmpty(filter.Gtin)) {
query = query.Where(x => x.BinItems.Any(o => o.UPC == filter.Gtin));
}
if (filter.WarehouseIds.Count() > 0) {
query = query.Where(x => filter.WarehouseIds.Contains(x.Zone.Id));
}
if (!string.IsNullOrEmpty(filter.Keywords)) {
query = query.Where(x => x.BinItems.Select(o => o.UPC).Contains(filter.Keywords));
}
query = query.Include(x => x.BinItems).Include(x => x.Zone);
if (!string.IsNullOrEmpty(filter.Keywords)) {
return await query.SumAsync(x => x.BinItems.Where(p => p.UPC.Contains(filter.Keywords)).Sum(o => o.Qty));
}
return await query.SumAsync(x => x.BinItems.Sum(o => o.Qty));
我抛出异常:
Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot perform an
aggregate function on an expression containing an aggregate or a
subquery.
它在 .NET Core 2.1 和 EF Core 2 中工作得很好,但现在我在使用这种方式执行的所有查询中不断遇到这些错误。
知道如何在 .NET Core 3.0/EF Core 2 中完成这项工作吗?
问题是嵌套聚合(在本例中,Sum
of Sum
)。 EF Core 3.0 仍然无法正确转换此类聚合。它很可能在 3.0 之前的版本中工作,客户端评估已在 3.0 中删除。
解决方案与往常一样避免嵌套聚合并在展平(通过 SelectMany
)集上执行单个聚合。它适用于除 Average
.
之外的所有标准分组聚合
这里是问题查询的解决方案(注意 Include
是不必要的,因为查询是在服务器端执行的):
var query = _binRepository.Table;
// ... (query filters)
var innerQuery = query.SelectMany(x => x.BinItems);
if (!string.IsNullOrEmpty(filter.Keywords)) {
innerQuery = innerQuery.Where(x => x.UPC.Contains(filter.Keywords));
}
return await innerQuery.SumAsync(x => x.Qty);
我正在升级到 EF Core 3.0 和 .NET Core 3.0,但我的一些查询停止工作。这是一个例子:
我有一个名为 Bins
的 table,我有另一个名为 BinItems
的 table,现在它当然是一对多关系。 BinItems
有一个名为 Qty
的 属性,我想根据客户在过滤器中给出的条件总结 BinItems
中的所有 Qty
。
代码如下:
var query = _binRepository.Table;
if (filter.LastRecountDate != null) {
query = query.Where(x => x.LastRecountDate.Date == filter.LastRecountDate.Value.Date);
}
if (filter.StartRecountDate != null) {
query = query.Where(x => x.LastRecountDate.Date >= filter.StartRecountDate.Value.Date);
}
if (filter.EndRecountDate != null) {
query = query.Where(x => x.LastRecountDate.Date <= filter.EndRecountDate.Value.Date);
}
if (filter.Active != null) {
query = query.Where(x => x.Active == filter.Active);
}
if (!string.IsNullOrEmpty(filter.BinLocation)) {
query = query.Where(x => x.BinLocation == filter.BinLocation);
}
if (!string.IsNullOrEmpty(filter.Gtin)) {
query = query.Where(x => x.BinItems.Any(o => o.UPC == filter.Gtin));
}
if (filter.WarehouseIds.Count() > 0) {
query = query.Where(x => filter.WarehouseIds.Contains(x.Zone.Id));
}
if (!string.IsNullOrEmpty(filter.Keywords)) {
query = query.Where(x => x.BinItems.Select(o => o.UPC).Contains(filter.Keywords));
}
query = query.Include(x => x.BinItems).Include(x => x.Zone);
if (!string.IsNullOrEmpty(filter.Keywords)) {
return await query.SumAsync(x => x.BinItems.Where(p => p.UPC.Contains(filter.Keywords)).Sum(o => o.Qty));
}
return await query.SumAsync(x => x.BinItems.Sum(o => o.Qty));
我抛出异常:
Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
它在 .NET Core 2.1 和 EF Core 2 中工作得很好,但现在我在使用这种方式执行的所有查询中不断遇到这些错误。
知道如何在 .NET Core 3.0/EF Core 2 中完成这项工作吗?
问题是嵌套聚合(在本例中,Sum
of Sum
)。 EF Core 3.0 仍然无法正确转换此类聚合。它很可能在 3.0 之前的版本中工作,客户端评估已在 3.0 中删除。
解决方案与往常一样避免嵌套聚合并在展平(通过 SelectMany
)集上执行单个聚合。它适用于除 Average
.
这里是问题查询的解决方案(注意 Include
是不必要的,因为查询是在服务器端执行的):
var query = _binRepository.Table;
// ... (query filters)
var innerQuery = query.SelectMany(x => x.BinItems);
if (!string.IsNullOrEmpty(filter.Keywords)) {
innerQuery = innerQuery.Where(x => x.UPC.Contains(filter.Keywords));
}
return await innerQuery.SumAsync(x => x.Qty);