EF Core调用SumAsync对SQL Server float字段求和出现精度误差如何解决
问题根因
你遇到的精度误差是浮点数存储特性导致的:SQL Server的float类型和C#的double类型都属于二进制浮点数,无法精确存储所有十进制小数,40.005这类十进制小数在二进制存储时会产生微小的误差,累加后误差就会显现出来。
可行解决方案
- 最优方案:调整字段类型为精确十进制类型
如果你的业务场景涉及库存、金额等需要精确计算的数值,建议直接修改数据库字段和实体属性类型:
- 将SQL Server中
Quantite字段从float改为decimal,可根据业务需求指定精度,比如decimal(18,3)即可满足3位小数的存储需求 - 将EF Core实体中
Quantite属性的类型从double改为decimal
修改后的求和代码不需要额外转换,即可得到精确结果:
public async Task<decimal> ObtenirTotalStockParSiteAsync(long siteId) => await Queryable.Where(snapshot => snapshot.SiteId == siteId) .SumAsync(snapshot => snapshot.Quantite) .ConfigureAwait(false);
- 临时兼容方案:查询时转换为decimal再求和
如果暂时无法修改数据库字段结构,可以在EF Core查询中将float值转换为decimal后再执行求和,该转换可被EF Core正确翻译为SQL层面的类型转换,避免累加误差:
public async Task<decimal> ObtenirTotalStockParSiteAsync(long siteId) => await Queryable.Where(snapshot => snapshot.SiteId == siteId) .SumAsync(snapshot => (decimal)snapshot.Quantite) .ConfigureAwait(false);
- 应急修复方案:对返回结果做精度舍入
如果不想修改现有代码的返回值类型,可以在拿到求和后的double结果后,按业务需要的小数位做四舍五入:
public async Task<double> ObtenirTotalStockParSiteAsync(long siteId) => Math.Round(await Queryable.Where(snapshot => snapshot.SiteId == siteId) .SumAsync(snapshot => snapshot.Quantite) .ConfigureAwait(false), 3);
内容的提问来源于stack exchange,提问作者oumechtak
相关产品推荐
相关产品推荐

