【发布时间】:2016-03-29 09:50:00
【问题描述】:
EF6 在将整数列与十进制值相乘和相加时处理舍入的方式似乎不一致。
// CREATE TABLE MyTable (MyIntValue INT NOT NULL)
// INSERT INTO MyTable (MyIntValue) VALUES (10)
const int IntScale = 5;
const decimal DecimalScale = 5;
const decimal DecimalScale2 = 5.0m;
context.Set<MyTable>()
.Select(row => new
{
WithFloats = 0.5f + (row.MyIntValue * 5.0f), // 50.5
WithDecimals = 0.5m + (row.MyIntValue * 5.0m), // 51
WithDecimals2 = 0.5m + ((decimal)row.MyIntValue * 5.0m), // 50.5
WithDecimals3 = 0.5m + ((decimal)row.MyIntValue * IntScale), // 51
WithDecimals4 = 0.5m + ((decimal)row.MyIntValue * (decimal)IntScale) // 51
WithDecimals5 = 0.5m + ((decimal)row.MyIntValue * DecimalScale) // 51
WithDecimals6 = 0.5m + ((decimal)row.MyIntValue * DecimalScale2) // 50.5
})
.Single();
这肯定不是预期/正确的行为吗?我希望 WithDecimals 值为 50.5(不是 51)。我忽略了一些简单的事情吗?在不更改其他常量的类型的情况下,如何确保 WithoutDecimals 不会四舍五入?
为 WithFloats 和 WithDecimals 生成的 SQL(分别):
,CAST(0.5 AS REAL) + (CAST(MyIntValue AS REAL) * CAST(5 AS REAL)) AS WithFloats
,0.5 + (CAST(MyIntValue AS DECIMAL(19,0)) * CAST(5 AS DECIMAL(18))) AS WithDecimals
【问题讨论】:
-
EF 默认将 System.Decimal 映射到 DECIMAL(18, 0),因此您的 WithDecimals 值会四舍五入为最接近的整数。我相信有一种方法可以改变这种默认行为,参见例如此评论:stackoverflow.com/a/27418286/189572
-
@Max:添加默认小数精度似乎没有效果。此外,如果您要使用以下表达式添加另一个投影列:(0.5m + row.MyIntValue),结果将为 10.5,因此该行为似乎不是由默认小数精度引起的。
-
有趣。看起来将 row.MyIntValue 转换为 DECIMAL(19,0) 是问题所在,它与转换为 DECIMAL(18) 一起工作。在 C# 中将其转换为十进制会发生什么?
WithDecimals = 0.5m + ((decimal)row.MyIntValue * 5.0m) -
如果您使用
CAST(0.5 AS REAL),也会自行修复。虽然我看不出本质上评估0.5 + 50可能是一个精确问题(decimal(18)应该很多)。CAST(10 AS DECIMAL(18,1)也可以。 -
@Max:将 int 列转换为似乎会产生正确的输出,但这仅适用于列而不适用于常量。我已经更新了原始问题以反映这一点。这在我看来仍然很不一致。
标签: c# entity-framework decimal rounding