2015-01-22 3 views
0

У меня есть приложение C#, которое записывает некоторые данные в базу данных SQLite, проблема возникает, когда я пытаюсь сохранить двойной C# в SQLite REAL.Comma vs dot as decimal separator

Он сохраняет его в базу данных с запятой в виде разделителя (как обычно, в моей стране, не уверен, что он рассчитывает на что угодно).

Таблица имеет следующую структуру:

CREATE TABLE `valoresStock` (
    `Fecha` TEXT, 
    `IdArticulo` TEXT, 
    `IdColor` INTEGER, 
    `KgPorUnidad` REAL, 
    `Stock` REAL, 
    `CostePorKg` REAL, 
    `CostePorUnidad` REAL, 
    PRIMARY KEY(Fecha,IdArticulo,IdColor) 
); 

и запрос я использую в моем приложении является следующее:

cmd.CommandText = "INSERT INTO valoresStock (Fecha, IdArticulo, IdColor, KgPorUnidad, Stock, CostePorKg, costePorUnidad) VALUES ('" + DateTime.Today + "','" + referencia.idArticulo + "', '" + referencia.idColor + "', '" + referencia.kilos + "', '" + referencia.stockActual + "', '" + referencia.valorPorKg + "', '" + referencia.valorPorUnidad + "') "; 

Как я уже сказал, последние четыре поля имеют типа двойной. Ошибка не указана.

Затем данные хранятся следующим образом:

data structure

То есть, используя точку, когда он не имеет дробной части, и запятая, когда он делает.

Проблема с этим, например, когда я использую ЗЕЬЕСТ для расчета, например, как это:

SELECT VS.Fecha, VS.IdArticulo, VS.IdColor, (VS.Stock * (VS.CostePorUnidad + VS.CostePorKg * Vs.KgPorUnidad)) AS Valor FROM valoresStock VS 

Это дает следующий результат, который является неправильным (только взял номер с точкой).

error with commas

Так что если я вручную изменить запятые для точек в моей таблице, она работает должным образом.

all with dots

Но как сделать мое приложение сделать это, своего рода изменения культуры?

Или я могу заставить SQLite понять или автоматически преобразовать запятую?

Почему SQLite принимает это число как действительное, если оно не понимает его позже?

+3

Еще одна возможность, где вы должны использовать параметризованные запросы. –

+0

Не могли бы вы объяснить себя дальше? – Pinx0

+0

Я описал это в ответ. –

ответ

6

Вы должны использовать параметризованный запрос для вставки значений. Это означает, что вы должны использовать только метки параметров в своей строке SQL и добавлять фактические значения в качестве параметров запроса.

Как правило, это хорошая практика для предотвращения атак SQL-инъекций. Хотя эти проблемы могут быть менее важными, если все ваши значения являются численными (и, возможно, даже не приходят непосредственно с пользовательского ввода), эта параметризация также служит для обеспечения того, чтобы значения параметров отформатировались так же, как целевой движок хочет/нуждается в них. Числа с плавающей запятой будут распознаны без необходимости беспокоиться о правильном разделителе с разделителями, и строки будут распознаны, если вам не придется беспокоиться о правильных кавычках и экранах.

Итак, ваше INSERT заявление должно быть изменено следующим образом:

cmd.CommandText = "INSERT INTO valoresStock (Fecha, IdArticulo, IdColor, KgPorUnidad, Stock, CostePorKg, costePorUnidad)" 
    + "VALUES (@fecha, @idArticulo, @idColor, @kgPorUnidad, @stock, @costePorKg, @costePorUnidad)"; 

Затем, вы можете добавить свои значения параметров в команде, как это:

cmd.Parameters.AddWithValue("@fecha", DateTime.Today.ToString(System.Globalization.CultureInfo.InvariantCulture)); 
cmd.Parameters.AddWithValue("@idArticulo", referencia.idArticulo); 
cmd.Parameters.AddWithValue("@idColor", referencia.idColor); 
cmd.Parameters.AddWithValue("@kgPorUnidad", referencia.kilos); 
cmd.Parameters.AddWithValue("@stock", referencia.stockActual); 
cmd.Parameters.AddWithValue("@costePorKg", referencia.valorPorKg); 
cmd.Parameters.AddWithValue("@costePorUnidad", referencia.valorPorUnidad); 

Все значения с плавающей точкой будет тогда автоматически распознаются для того, что они есть и хранятся надлежащим образом.

Одна вещь, чтобы отметить, что я явно конвертируется DateTime.Today в строку по двум причинам:

  • DateTime не является примитивным типом, так что я не совсем уверен, что ядро ​​базы данных будет делать с ним ,
  • Вы указали столбец Fecha как имеющий тип TEXT, поэтому я предполагаю, что вам нужно текстовое представление даты в вашей базе данных, а не все, что можно «оценить».

Для того, чтобы гарантировать, что ваша программа записывает одни и те же данные, независимо от того, на какой машине она выполняется, я использовал InvariantCultureCultureInfo экземпляр, который обеспечивает, таким образом на выступление, «нейтральный» формат независимого настроек культуры текущего компьютера. Если у вас также есть программа, ожидающая этого формата, если вы когда-либо разбираете дату, файлы базы данных, написанные вашим приложением, всегда будут совместимы, даже если приложение используется на компьютерах с разными настройками культуры.

+0

Я объявлял Fecha как ТЕКСТ, потому что SQLite не имеет типа данных для дат, как описано здесь: https://www.sqlite.org/datatype3.html Итак, я следовал его рекомендации использовать TEXT в качестве строк ISO8601 ("YYYY- MM-DD HH: MM: SS.SSS "). – Pinx0

+0

@ Pinx0: Oh rigt; в этом случае, а не 'ToString (System.Globalization.CultureInfo.InvariantCulture)', вы можете преобразовать 'DateTime' в один из поддерживаемых форматов, например. явно указывая соответствующую строку формата. [Этот вопрос SO] (http://stackoverflow.com/questions/249760/how-to-convert-unix-timestamp-to-datetime-and-vice-versa) предоставляет другой метод. –

0

Я бы решил проблему на стороне .NET, а не на стороне базы данных.

В .NET форматирование чисел зависит от культуры. Например:

// This prints 2.3 - Neutral, invariant culture (English notation) 
string withDot = (2.3d).ToString(CultureInfo.InvariantCulture.NumberFormat); 

// This prints 2,3 - Spanish culture 
string withComma = (2.3d).ToString(new CultureInfo("es-ES"));