LINQ取模运算报float类型无效 如何转int实现千位四舍五入
报错根因
你当前使用的是会被ORM(EF/EF Core等)翻译为SQL语句执行的LINQ查询,代码中Math.Round(b.CostReproductionNew.Value)的返回值仍是映射为SQL浮点类型的float值,而SQL语法中float类型不支持%取模运算符,因此抛出类型不兼容的异常。
修复方案
方案1:数据库端显式类型转换(推荐,性能更好)
在参与取模运算前,将Math.Round处理后的浮点值显式转换为int类型,ORM会自动将这个转换翻译为SQL侧的整数类型转换逻辑,转换后即可正常执行取模运算。
修正后的代码如下:
allBuildings.Sum(b => // 优先取大于0的BuildingOverride有效值 b.BuildingOverride is > 0 ? b.BuildingOverride.Value : b.CostReproductionNew.HasValue ? ( // 显式转整数,解决float无法取模的问题 int roundedVal = (int)Math.Round(b.CostReproductionNew.Value); roundedVal > 500 ? roundedVal % 1000 >= 500 ? roundedVal + 1000 - roundedVal % 1000 : roundedVal - roundedVal % 1000 : 500 ) : 0 );
如果你的开发环境不支持C# 7+的Lambda内变量声明,可以直接在每处参与运算的位置重复写(int)Math.Round(b.CostReproductionNew.Value)即可,逻辑完全一致。
方案2:内存侧计算(适配ORM版本不兼容转换的场景)
如果你的ORM版本对int类型转换的SQL翻译支持有问题,可以调用AsEnumerable()先把需要的字段加载到应用内存,后续计算完全走C#原生逻辑——C#原生支持float类型取模,不会触发SQL侧的类型报错。
代码如下:
allBuildings // 切换到内存计算 .AsEnumerable() .Sum(b => b.BuildingOverride is > 0 ? b.BuildingOverride.Value : b.CostReproductionNew.HasValue ? ( float roundedVal = Math.Round(b.CostReproductionNew.Value); roundedVal > 500 ? roundedVal % 1000 >= 500 ? roundedVal + 1000 - roundedVal % 1000 : roundedVal - roundedVal % 1000 : 500 ) : 0 );
注意:方案2会把目标表的相关字段全量加载到应用内存,如果表数据量很大,性能会明显低于方案1,优先选择显式类型转换的方案。
内容的提问来源于stack exchange,提问作者Nikhil Venkat
相关产品推荐
相关产品推荐

