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);