【问题标题】:OverflowException when converting SqlDecimal to Decimal将 SqlDecimal 转换为 Decimal 时的 OverflowException
【发布时间】:2016-09-23 19:20:18
【问题描述】:

在我们的实际应用程序中,当尝试将 SqlDecimal 的值 99 转换为 System.Decimal 时,我们会得到一个 OverflowException。因为SqlDecimal的精度高于System.Decimal的精度,所以抛出异常。

这是一个重现问题的测试:

[Test]
public void SqlDecimalToDecimalOverflowTest()
{
    // in our real application d1 & d2 are loaded from a database; both are declared as DECIMAL(28, 5)
    // for test purposes I recreate identical SqlDecimal objects here:
    var d1 = new SqlDecimal(28, 5, true, 9900000, 0, 0, 0); // Debugger shows {99.00000}
    var d2 = new SqlDecimal(28, 5, true, 100000, 0, 0, 0); // Debugger shows {1.00000}

    var d3 = d1.Value / d2; // Debugger shows d1.Value as {99}, d1.Value is of type decimal (not SqlDecimal)
    var exception = d3.Value; // Debugger shows d3 as {99.0000000000000000000000000000000}
}

截图:

问题是:
将此类 SqlDecimal 对象转换为 Decimal 的最快方法是什么?

前段时间我写了这个辅助方法:

public static SqlDecimal RecreateWithMinPrecScale(this SqlDecimal value)
{
    string s = value.Scale > 0 ? value.ToString().TrimEnd('0') : value.ToString();
    int delimiterIndex = s.IndexOf(".");
    int precision = s.Length - (delimiterIndex >= 0 ? 1 : 0) - (s.StartsWith("-") ? 1 : 0);
    int scale = delimiterIndex >= 0 ? s.Length - 1 - delimiterIndex : 0;
    return SqlDecimal.ConvertToPrecScale(value, precision, scale);
}

所以我可以写

var ok = d3.RecreateWithMinPrecScale().Value; // no exception

但显然这是一种缓慢且低效的方法,我们需要进行数十亿次这样的计算。

请不要讨论为什么我们使用 SqlDecimal 类而不仅仅是 System.Decimal(它是一个金融应用程序,我相信以前我们需要支持非常长的数字(无论是大的还是精确的),据说 28- System.Decimal 29 位可能不够)。

【问题讨论】:

    标签: c# .net sql-server exception decimal


    【解决方案1】:

    你应该在除法操作后恢复d3中的精度和比例属性的值:

    var d3 = d1.Value / d2;
    d3 = SqlDecimal.ConvertToPrecScale(d3, 28, 5);
    

    【讨论】:

    • 谢谢你,鲁斯塔姆。在我们的例子中,是的,我们可以使用 ConvertToPrecScale() 并指定正确的精度和比例,因为我们在生成的数据模型的属性中具有此信息。但是如果我想要一个通用的解决方案并且不知道精度和规模怎么办?我的意思是,如果我只想从数字中删除额外/不必要的比例(就像我的 RecreateWithMinPrecScale() 方法所做的那样)怎么办?
    猜你喜欢
    • 1970-01-01
    • 2019-01-22
    • 2017-04-15
    • 1970-01-01
    • 2021-08-31
    • 2020-10-14
    • 1970-01-01
    • 2012-07-13
    • 2018-09-22
    相关资源
    最近更新 更多