将SqlDecimal转换为Decimal时出现溢出

时间:2016-05-26 00:42:54

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

在我们的实际应用程序中,我们在尝试将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}
}

截图:

Debugging a unit test

问题是:
将此类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(它是一个金融应用程序,我相信以前我们有要求支持很长的数字(大或精))据说System.Decimal的28-29位数字可能不够。)

1 个答案:

答案 0 :(得分:2)

您应该在除法运算后恢复d3中精度和比例属性的值:

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