【问题标题】:Entity Framework decimal rounding inconsistent in projection投影中的实体框架小数舍入不一致
【发布时间】: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


【解决方案1】:

使用数据注释显式定义列类型,以及小数字段的精度和小数位数

[Column(TypeName = "decimal(5,2)")]
public decimal MyDecimal { get; set; }

您可以找到默认的 LINQ-to-SQL CLR 类型映射,在使用 EF 时适用,here

阅读 T-SQL 数字和十进制数据类型here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-08
    • 1970-01-01
    相关资源
    最近更新 更多