EF Core 2.2 LINQ多列聚合函数生成SQL错误致结果异常
解决EF Core 2.2中LINQ多列聚合SQL翻译错误的问题
这是EF Core 2.2版本里一个已知的查询翻译bug——当你在GroupBy后的Select中对多个字段使用聚合函数时,部分Sum调用没有被正确翻译成SQL的SUM(),反而被错误地处理为直接取分组内某一行的原始字段值,这就导致了你看到的结果错误。
问题分析
从你提供的生成SQL可以看到,只有SumInvoiceQty和SumBasePoints被正确转换为SUM()聚合,而其他字段比如TotalMRPAmount直接取了i.TotalMRPAmount,这显然不符合分组聚合的逻辑,最终只会返回分组内某一行的该字段值,而非总和。
解决方案
针对EF Core 2.2的兼容方案,你可以尝试以下两种方法:
方法1:简化GroupBy的分组键,提前投影需要的字段
将GroupBy的匿名类分组键替换为单个字段(因为你本来只按SecondaryInvoiceId分组),同时先投影出所有需要聚合的字段,帮助EF Core正确识别聚合操作:
public async Task<SecondaryInvoiceLProformaTotals> test(int secondaryInvoiceId) { var query = (_context.SecondaryInvoiceLineItems .Where(i => i.SecondaryInvoiceId == secondaryInvoiceId) // 提前投影所有需要聚合的字段,减少EF翻译的歧义 .Select(i => new { i.SecondaryInvoiceId, i.InvoiceQty, i.TotalMRPAmount, i.TotalSecondaryDiscountAmount, i.TotalSecondaryPrice, i.TotalIGSTAmount, i.TotalCGSTAmount, i.TotalSGSTAmount, i.TotalAmount, i.TotalBasePoints }) // 直接按单个字段分组,替代匿名类 .GroupBy(l => l.SecondaryInvoiceId) .Select(g => new SecondaryInvoiceLProformaTotals { SecondaryInvoiceId = g.Key, SumInvoiceQty = g.Sum(o => o.InvoiceQty), SumMRPAmount = g.Sum(o => o.TotalMRPAmount), SumSecondaryDiscountAmount = g.Sum(o => o.TotalSecondaryDiscountAmount), SumSecondaryPrice = g.Sum(o => o.TotalSecondaryPrice), SumIGSTAmount = g.Sum(o => o.TotalIGSTAmount), SumCGSTAmount = g.Sum(o => o.TotalCGSTAmount), SumSGSTAmount = g.Sum(o => o.TotalSGSTAmount), SumAmount = g.Sum(o => o.TotalAmount), SumBasePoints = g.Sum(o => o.TotalBasePoints) }) ); SecondaryInvoiceLProformaTotals ret = await query.FirstOrDefaultAsync(); return ret; }
方法2:升级EF Core版本(推荐)
EF Core 2.2属于比较老旧的版本,后续的3.0+版本修复了大量查询翻译的bug,包括这类多列聚合的问题。如果项目允许,建议升级到EF Core 3.1或更高版本,你的原始代码在新版本中应该能直接生成符合预期的SQL。
验证效果
修改后生成的SQL应该会和你期望的一致,所有需要聚合的字段都会被包裹在SUM()函数中,确保计算的是分组内的总和而非单一行的值。
内容的提问来源于stack exchange,提问作者sagarpdesai
相关产品推荐
相关产品推荐

