EF Core中.HasPrecision(18,2)为何不对计算列进行四舍五入?
问题原因及解决办法
为什么HasPrecision(18,2)未生效?
HasPrecision(18,2)仅用于告诉EF Core将TotalPrice列映射为SQL Server的decimal(18,2)类型,但它不会干预计算列的表达式运算逻辑。你的问题根源有两点:
- 表达式中使用了浮点数常量
60.0,导致DurationInMinutes / 60.0的运算以浮点数精度执行,浮点数的固有精度误差会生成类似18.49998的近似值,即使最终转换为decimal(18,2),这些近似值也会保留。 - SQL Server不会自动对计算结果进行四舍五入,仅会将计算后的结果强制转换为列定义的类型,浮点数的近似值转换后仍会显示多位小数。
解决办法
要让SQL Server将计算结果四舍五入或截断至两位小数,必须在计算表达式中显式处理:
1. 四舍五入到两位小数(推荐)
修改计算表达式,使用ROUND函数,并确保运算全程使用decimal类型避免浮点数误差:
modelBuilder .Entity<Service>() .Property(u => u.TotalPrice) .HasComputedColumnSql("ROUND([Price] * ([DurationInMinutes] / CAST(60 AS DECIMAL(18,2))), 2)") .HasPrecision(18, 2);
CAST(60 AS DECIMAL(18,2))确保除法运算使用decimal精度,消除浮点数误差。ROUND(..., 2)强制将计算结果四舍五入到两位小数。
2. 截断到两位小数(不四舍五入)
若不需要四舍五入,直接截断小数部分,可使用CAST转换:
modelBuilder .Entity<Service>() .Property(u => u.TotalPrice) .HasComputedColumnSql("CAST([Price] * ([DurationInMinutes] / CAST(60 AS DECIMAL(18,2))) AS DECIMAL(18,2))") .HasPrecision(18, 2);
该方式会直接舍弃两位小数后的部分,例如18.49998会被转换为18.49。
注意事项
- 计算表达式中避免使用浮点数常量(如
60.0),改用decimal类型的常量或转换操作,防止浮点数精度误差。 HasPrecision(18,2)仍需保留,它负责定义数据库列的最终数据类型,确保存储和读取时的精度符合预期。
内容的提问来源于stack exchange,提问作者MiddleEasternG
相关产品推荐
相关产品推荐

