Я пишу процедуру, которая проверяет данные перед их вставкой в базу данных, и один из шагов - проверить, соответствуют ли числовые значения точности и масштабу типа SQL-Server Numeric (x, y).
У меня уже есть точность и масштаб от SQL-Server, но каков наиболее эффективный способ в C# получить точность и масштаб значения CLR или, по крайней мере, проверить, соответствует ли оно заданному ограничению?
На данный момент я конвертирую значение CLR в строку, а затем ищу расположение десятичной точки с помощью .IndexOf (). Есть ли более быстрый способ?





Вы можете использовать decimal.Truncate (val), чтобы получить целую часть значения, и decimal.Remainder (val, 1), чтобы получить часть после десятичной точки, а затем проверьте, что каждая часть соответствует вашим ограничениям (я предполагаю, что это может будь простой> или <проверка)
System.Data.SqlTypes.SqlDecimal.ConvertToPrecScale( new SqlDecimal (1234.56789), 8, 2)
дает 1234,67. он будет усекать лишние цифры после десятичного разряда и выдает ошибку, а не пытается усечь цифры перед десятичным знаком (например, ConvertToPrecScale (12344234, 5,2)
Не вызывая исключения, вы можете использовать следующий метод, чтобы определить, соответствует ли значение ограничениям точности и масштаба.
private static bool IsValid(decimal value, byte precision, byte scale)
{
var sqlDecimal = new SqlDecimal(value);
var actualDigitsToLeftOfDecimal = sqlDecimal.Precision - sqlDecimal.Scale;
var allowedDigitsToLeftOfDecimal = precision - scale;
return
actualDigitsToLeftOfDecimal <= allowedDigitsToLeftOfDecimal &&
sqlDecimal.Scale <= scale;
}
Вот подход, основанный на математике.
private static bool IsValidSqlDecimal(decimal value, int precision, int scale)
{
var minOverflowValue = (decimal)Math.Pow(10, precision - scale) - (decimal)Math.Pow(10, -scale) / 2;
return Math.Abs(value) < minOverflowValue;
}
При этом учитывается, как sql server будет выполнять округление и предотвращать ошибки переполнения, даже если мы превысим точность. Например:
DECLARE @value decimal(10,2)
SET @value = 99999999.99499 -- Works
SET @value = 99999999.995 -- Error
1234.57, но я все равно проголосовал за вас, потому что это отличный ответ.