2016-05-26 12 views
2

In unserer realen Anwendung erhalten wir eine OverflowException, wenn Sie versuchen, SqlDecimal Wert von 99 in System.Decimal zu konvertieren. Die Ausnahme wird ausgelöst, da die Genauigkeit von SqlDecimal höher ist als die Genauigkeit von System.Decimal. HierOverflowException beim Konvertieren von SqlDecimal in Dezimal

ist ein Test, der das Problem reproduziert:

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

Ein Screenshot:

Debugging a unit test

Die Frage ist:
Was ist der schnellste Weg, um solche SqlDecimal Objekte zu konvertieren Dezimal?

Vor einiger Zeit habe ich diese Hilfsmethode schrieb:

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 kann ich

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

schreiben Aber natürlich ist dies eine langsame und ineffiziente Methode, und wir brauchen Milliarden solcher Berechnungen zu tun .

Bitte lassen Sie uns nicht diskutieren, warum wir SqlDecimal Klasse und nicht nur System.Decimal verwenden (es ist eine finanzielle Anwendung und ich glaube früher hatten wir Anforderungen, sehr lange Zahlen zu unterstützen (entweder groß oder präzise) und es wurde gesagt, dass 28 -29 Ziffern von System.Decimal können nicht genug sein).

Antwort

1

Sie sollten Werte der Präzision wiederherstellen und Skalenattribute im d3 nach der Divisionsoperation:

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

Danke, Rustam. In unserem Fall können wir ConvertToPrecScale() verwenden und die korrekte Genauigkeit und Skalierung angeben, da diese Informationen im Attribut in unserem generierten Datenmodell enthalten sind. Aber was, wenn ich eine allgemeine Lösung möchte und nicht die Präzision und den Maßstab kenne? Ich meine, was ist, wenn ich nur extra/unnötige Skalierung von der Zahl entfernen möchte (wie meine RecreateWithMinPrecScale() Methode)? – nightcoder

Verwandte Themen