将SqlDecimal转换为Decimal时发生OverflowException [英] OverflowException when converting SqlDecimal to Decimal

查看:878
本文介绍了将SqlDecimal转换为Decimal时发生OverflowException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我们的实际应用程序中,当尝试转换



问题是:

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



前段时间,我编写了此辅助方法:

 公共静态SqlDecimal RecreateWithMinPrecScale(此SqlDecimal值)
{
字符串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;
返回SqlDecimal.ConvertToPrecScale(value,precision,scale);
}

所以我可以写

  var ok = d3.RecreateWithMinPrecScale()。Value; //也不例外

但是显然这是一种缓慢而低效的方法,我们需要做数十亿个这样的工作计算。



请让我们不要讨论为什么我们使用SqlDecimal类而不是System.Decimal类(这是一个财务应用程序,我相信以前我们对支持很长的要求数字(无论是大数字还是精确数字),据说System.Decimal的28-29位数字是不够的。)

解决方案

您应该在除法运算之后,在 d3 中恢复精度和小数位属性的值:

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


In our real application we get an OverflowException when trying to convert SqlDecimal value of 99 to System.Decimal. The exception is thrown because SqlDecimal's precision is higher than System.Decimal's precision.

Here is a test that reproduces the issue:

[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}
}

A screenshot:

The question is:
What is the fastest way to convert such SqlDecimal objects to Decimal?

Some time ago I wrote this helper method:

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);
}

so I can write

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

But obviously this is a slow and inefficient method and we need to do billions of such calculations.

Please, let us not discuss why we use SqlDecimal class and not just System.Decimal (it's a financial application and I believe previously we had requirements to support very long numbers (either large or precise) and it was said that 28-29 digits of System.Decimal can be not enough).

解决方案

You should restore values of the precision and scale attributes in the d3 after the divide operation:

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

这篇关于将SqlDecimal转换为Decimal时发生OverflowException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆