EF Core 3.1拥有对象属性求和报错,2.1版本可正常运行
解决EF Core 3.1升级后的InvalidCastException问题
我来帮你搞定这个升级后的报错问题——EF Core 3.0及以后版本对查询翻译的规则做了非常大的调整,尤其是客户端评估的限制和子查询处理逻辑的变化,这就是你从2.1升级到3.1后遇到这个异常的核心原因。
先看你的代码:
var ordersCounts = await ordersCountsQuery .Select(x => new TransactionDTO { Value = new MoneyDTO(ordersCountsQuery.Sum(a => a.TotalPrice.Amount)) }) .FirstOrDefaultAsync();
这里的问题在于,你在Select的投影表达式里直接引用了外层的ordersCountsQuery来执行Sum计算。EF Core 2.1时期,即便你开启了QueryClientEvaluationWarning,这种场景下它可能还是会偷偷把Sum操作放到客户端(内存)来执行,不会触发警告或报错;但3.1的查询翻译器会尝试把整个表达式转换成SQL,它无法正确解析这种嵌套引用的构造,就抛出了InvalidCastException。
给你两种可行的修复方案:
方案1:先计算聚合值,再构造DTO(最直接)
先单独算出总和,再用这个值来创建目标DTO,彻底避免在投影里嵌套整个查询:
var totalAmount = await ordersCountsQuery.SumAsync(a => a.TotalPrice.Amount); var ordersCounts = new TransactionDTO { Value = new MoneyDTO(totalAmount) };
这种方式逻辑清晰,适合你只需要这一个聚合结果的场景。
方案2:用虚拟分组实现投影内的聚合(适合复杂场景)
如果你的实际场景需要在更复杂的投影中包含聚合结果,可以用GroupBy创建一个虚拟分组,把所有数据归为一组,然后在分组后的投影里计算Sum:
var ordersCounts = await ordersCountsQuery .GroupBy(x => 1) // 虚拟分组,将所有行合并为一组 .Select(g => new TransactionDTO { Value = new MoneyDTO(g.Sum(a => a.TotalPrice.Amount)) }) .FirstOrDefaultAsync();
这种写法能让EF Core正确将聚合操作翻译成SQL,避免客户端评估和类型转换异常。
简单总结下:EF Core 3.x对查询翻译的严格性远高于2.x,它不再允许很多2.x里能“侥幸”通过的客户端评估场景,所以我们需要调整写法,让查询逻辑能被正确翻译成SQL。
内容的提问来源于stack exchange,提问作者Deivydas Voroneckis
相关产品推荐
相关产品推荐

