Десетична стойност 1,5 завършва като 15 в DB - как, защо?

Поздрави добри хора от интернет :)

Имам стойност на низ "1,5", която след Convert.ToDecimal() завършва като 1,5M, когато я гледам в програмата за отстраняване на грешки. Дотук добре предполагам. След това десетичната стойност се предава на извикване на съхранена процедура в набор от данни. Типът параметър, който ме интересува, е дефиниран като NUMBER (7,2) в DB, ​​така че трябва да позволява числа, които имат цифри след десетичния разделител.

Проблемът е, че някъде по линията десетичната стойност губи своя разделител и се присъединява към точността с мащаба, създавайки напълно ново число, както е посочено в заглавието на тази публикация. Дори се опитах да настроя Precision и Scale вътре в колекцията от параметри в това извикване на съхранена процедура, за да съответства на DB (7,2), но и това не помогна.

Имате ли представа какво може да се случва тук?

РЕДАКТИРАНЕ:

Ето кода, който извиква съхранената процедура:

CaseFactory.UtilsAdapter.SetCaseAction(DefId, action, doneBy, assignedTo, comment, status, searchStatus, priority, access, relStatus, relStatusFixKit, totalhrs, out Common.RETURN_CODE, out Common.RETURN_TEXT);

=> SetCaseAction просто извиква съхранена процедура в DB, ​​използвайки механиката на DataSet. 'totalhrs' е параметърът, който ме интересува, в този момент е десетичен знак 1,5M. Също така проверих NLS_NUMERIC_CHARACTERS в Oracle и те са зададени на ', '

Така че използва запетая за десетични знаци и интервал за хиляди. Нищо необичайно не виждам там. Единственото странно нещо може да е, че '1,5' завършва като '1.5M' с точка вътре след ToDecimal(), което може да се тълкува неправилно. Изглежда обаче малко вероятно, тъй като регионалните настройки на моя сървър също използват ',' като десетичен разделител, освен ако .NET не използва някои различни настройки? Наистина объркан.


person dream3n    schedule 27.07.2011    source източник
comment
След това десетичната стойност се предава на извикване на съхранена процедура в набор от данни. -› Не съм сигурен, че тази част е достатъчно ясна. Можете ли да споделите някакъв код, за да стане тази част ясна.   -  person Yiğit Yener    schedule 27.07.2011


Отговори (5)


Подозирам, че го преобразувате в даден момент без правилната култура, например свързвате го (вместо да използвате параметър) в TSQL заявка чрез ToString() или просто използвате грешната култура при извикване на ToDecimal. „1,5“ е двусмислено между „1 десетична точка 5“ и „1 разделител на групи 5“; последният случай се анализира като 15.

person Marc Gravell    schedule 27.07.2011
comment
OP каза, че когато той отстранява грешки, преобразуваната стойност се показва като 1.5M правилно, така че аз отивам за проблема ToString(). - person Thorsten Dittmar; 27.07.2011
comment
Не съм сигурен коя култура използваше, но със сигурност НЕ тази, която бях настроил на тази система в регионалните настройки. Както и да е, започнах трескаво да изпробвам различни култури и уточняването на финландската култура при извикването на ToDecimal() го направи вместо мен, така че ще трябва да приема този отговор, въпреки че все още не ми е ясно коя култура е била използвана първоначално. Благодаря - person dream3n; 29.07.2011
comment
@dream3n да повторя обаче; фактът, че културата имаше значение ми казва, че пишете заявката си погрешно. Трябва да използвате параметри. Те не страдат от проблеми с локализацията (и са по-безопасни от атака и позволяват повторно използване на плана) - person Marc Gravell; 29.07.2011
comment
@Marc, не съм сигурен, че разбирам мнението ви; Съхранените процедури на Ado.net ИЗПОЛЗВАТ параметри под капака. - person dream3n; 29.07.2011
comment
@dream3n да... но за да се случи тази грешка, някъде третирате това като низ, а не като десетичен знак / и т.н. - person Marc Gravell; 29.07.2011
comment
А, така е, но само защото го получавам като низ. Нямам влияние върху въвеждането на този параметър, когато пристигне. Все пак разбирам мнението ви и би трябвало да е най-добра практика да използвате десетичен знак от самото начало. наздраве - person dream3n; 29.07.2011

Предполагам, че това е проблем с локализацията - запетаите се използват за разделяне на хиляди, вместо за посочване на десетични знаци в много системи. Проверете езиковата настройка на вашата база данни.

person Dave    schedule 27.07.2011
comment
Странична бележка: ако стойността се предава на DB като параметър, културата не трябва да има значение. Но съм съгласна с общата диагноза. - person Marc Gravell; 27.07.2011

Десетичният разделител в SQL е ., а не ,. Така че 1,5 се тълкува като 15, а не 1,5. За да избегнете този вид проблем, винаги използвайте параметризирани заявки, вместо да кодирате стойностите директно в текста на заявката.

person Thomas Levesque    schedule 27.07.2011

Някои кодове за това как предавате стойността на съхранената процедура биха били полезни (ако го правите сами).

Някои хора все още използват String.Format за генериране на низове на заявки. Освен че причинява грешки като тази, която описвате, това е отворено за SQL инжекции.

Трябва да използвате параметризирани заявки. Обикновено правенето на нещо подобно ще работи:

SqlCommand cmd = new SqlCommand("...", connection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@myDecimal", decimalVariable);

РЕДАКТИРАНЕ
Разбира се, това не трябва да се прави само за някои от параметрите, а за всички параметри за съхранената процедура! Горното е само пример за това как да подадете параметри към съхранената процедура на първо място.

person Thorsten Dittmar    schedule 27.07.2011
comment
Съгласен - но ако се се окаже, че е така, тревожа се за другите непараметрични стойности. Конкатенацията не е добра (освен в контролирани сценарии). (това е бележка за OP, а не критика на този отговор) - person Marc Gravell; 27.07.2011
comment
Разбира се, това е само пример за това как изобщо да параметризирате заявка. Разбира се, AddWithValue трябва да се извика за всички параметри! - person Thorsten Dittmar; 27.07.2011

Както каза Томас, в SQL десетичният разделител в SQL е "."

В този случай можете просто да използвате:

yourVariable.Replace(',','.')

След това предайте параметъра на функцията, която извършва транзакцията.

person NicoRiff    schedule 27.07.2011
comment
вярно Какво ще кажете за компютрите в английското царство? Къде 1300,5 е валидно десетично число? Тогава ще завършите с 1.300.5 - какво трябва да е това? Толкова за разработването на софтуер, съобразено с културата :) - person Thorsten Dittmar; 27.07.2011
comment
Точно така, това решение работи в този строг случай (1,5) и подобни. - person NicoRiff; 27.07.2011