Лучший отвечающий
Access, неверные данные столбца

Вопрос
-
Добрый вечер! Сегодня выявил ошибку в своем приложении. В базе данных есть числовое поле "Двойное с плавающей точкой". Программа сохраняет туда данные даты в виде OADate. Получается число - "44233,7245479977". Проблема появилась на тех компьютерах, где стоит формат времени "Английский (США)". Как только выставляется этот формат времени в базе данных убирается запятая у числа. И программа получает уже число, которое не возможно перевести обратно в дату. Самое интересное, при смене формата времени в числе сразу появляется запятая. То есть она как бы есть...
Как решить эту проблему?
6 февраля 2021 г. 18:50
Ответы
-
Значения данных в запрос в любом случае нужно вставлять параметрами, не важно, строка это это или число. Да, если значение числовое, его нужно перевести в число с помощью той же культуры, с помощью которой его преобразовали в текст на сервере. Лучше использовать CultureInfo.InvariantCulture вместо ru-RU, так как загрузка русского языка может потребовать дополнительных ресурсов на не русскоязычной ОС, или вообще упасть с ошибкой, если какого-то пакета не хватает. Правильный подход именно такой.
- Предложено в качестве ответа Maksim MarinovMicrosoft contingent staff, Moderator 9 февраля 2021 г. 9:19
- Отменено предложение в качестве ответа Siompc 9 февраля 2021 г. 9:29
- Помечено в качестве ответа Siompc 10 февраля 2021 г. 19:12
9 февраля 2021 г. 3:34 -
Попробуйте сами, и увидите, получиться или нет. InvariantCulture - это почти то же самое, что en-us, только для нее гарантируется, что она всегда доступна и ее параметры не зависят от настроек системы и обновлений. То есть для передачи данных по сети это как раз то, что нужно. С использованием другой культуры может получиться, но до поры до времени.
- Помечено в качестве ответа Siompc 10 февраля 2021 г. 21:18
10 февраля 2021 г. 16:40
Все ответы
-
В формате США запятая - это разделитель тысяч, а разделитель десятичной части - точка. Сам Access эти форматы обрабатывает отлично. Ошибка где-то при преобразовании между текстом и числом в вашем коде.8 февраля 2021 г. 3:45
-
Я понял. Значение OADate получает сервер. И отправляет его клиенту. Отправляет число с запятой в виде строки. Access сохраняет его, соответственно, как число не дробное.
Получается при добавлении или обновлении данных таблицы нужно всегда проверять, является ли столбец типа DBTYPE_R8 и потом проверять регион, делать замену точки на запятую или обратно, затем только сохранять... Более простого способа нет? Например указать в таблице БД принудительно разделитель числа. Или еще как-нибудь?
И как проверить программно текущий разделитель дробных чисел?
8 февраля 2021 г. 9:44 -
Получить разделитель нашел как:
Dim tmp = Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator
Но вот костыль с Replace это не есть хорошо...
8 февраля 2021 г. 9:51 -
Этот подход в корне неверен. Access при использовании и ODBC, и OleDB умеет принимать сразу числовое значение нужного типа, никакого преобразования в строку вообще не должно фигурировать. Либо, если оно есть, оно должно осуществляться с предопределенным CultureInfo, так что бы разделитель был известен.8 февраля 2021 г. 10:18
-
Можно попробовать изменить тип данных на строку и сохранять в базу с запятой, а в самом приложении изменить CultureInfo при запуске, что бы переводило обратно В дату без ошибок. Но вот поле типа строка будет занимать значительно больше, чем число...8 февраля 2021 г. 10:19
-
Нет, это еще хуже. Надо передавать правильный CultureInfo в тот метод, который осуществяляет преобразование (Double.Parse, Double.ToString, ...), а не устанавливать глобально. В каких-то других методах может понадобиться именно системная культура.8 февраля 2021 г. 11:05
-
Ох как много кода придется переписать...
А что если сохранить сперва системную культуру в переменную, а потом при запуске приложения в Application.xaml изменить ее:
Private Sub Application_Startup(sender As Object, e As StartupEventArgs) Thread.CurrentThread.CurrentCulture = New Globalization.CultureInfo("ru-RU") End Sub
И если понадобится системная - брать ее из переменной? Такой способ сработает? И какие будут в дальнейшем подводные камни?
8 февраля 2021 г. 13:39 -
Это в каждом новом потоке нужно указывать новую культуру? 0_0 Да тут теперь месяц сидеть нужно, что бы все переделать
Опять же не получается. Вот приходит с сервера строка данных. У сервера разделитель запятая. В строке путь будет "123,45". Я выполняю запрос "INSERT INTO `t1` (`Число`) VALUES ('" & SERVDATA & "')"
В базе в итоге число "12345", потому что база опирается на системную культуру... Получается перед запросом нужно сперва преобразовать строку в число согласно культуре указанной в потоке, затем обратно в строку и выполнить запрос? Это жестоко
- Изменено Siompc 8 февраля 2021 г. 13:54
8 февраля 2021 г. 13:46 -
Этот код нужно выкинуть и переписать по нормальному. Здесь не преобразование в строку нужно, а использование параметризованных запросов: https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/configuring-parameters-and-parameter-data-types
Если запрос будет "INSERT INTO `t1` (`Число`) VALUES ('?')", а значение передается через параметр (cmd.Parameters.AdddWithValue("param",SERVDATA)),то проблемы со знаками разделителей не будет.
Как я уже написал, Access поддерживает передачу числовых значений напрямую, без преобразования в строку, нужно лишь правильно ей воспользоваться
8 февраля 2021 г. 16:13 -
Прошу мнение экспертов по костылю. Пока что ничего умнее не придумал. Сейчас данные идут только с сервера, на стороне клиента при сохранении в БД проверяется тип столбца и "правильно" составляется запрос...
If TypeColown(TableName, entryData.Key) = "DBTYPE_R8" Then tmpQueryData2 &= ",'" & Double.Parse(entryData.Value, New Globalization.CultureInfo("ru-RU")).ToString() & "'" Else tmpQueryData2 &= ",'" & entryData.Value & "'" End If
А потом уже все потоки используют системную Culture для работы с данными
- Изменено Siompc 8 февраля 2021 г. 16:25 я тупой
8 февраля 2021 г. 16:23 -
Странно, не видел этого ответа ранее. Только сейчас загрузился. Спасибо за информацию.
Наверное так тоже не получится. Потому что передать в качестве параметров нужно именно Double
Дело в том, что данные с сервера уже приходят в виде строки. Они могут быть как текстом, так и числом. Клиент просто принимает строку и разбивает ее на множество пар "заголовок-значение". Поэтому этот текст в любом случае придется сперва правильно перевести в число, а потом передавать в качестве параметра. Так ведь?
8 февраля 2021 г. 22:21 -
Значения данных в запрос в любом случае нужно вставлять параметрами, не важно, строка это это или число. Да, если значение числовое, его нужно перевести в число с помощью той же культуры, с помощью которой его преобразовали в текст на сервере. Лучше использовать CultureInfo.InvariantCulture вместо ru-RU, так как загрузка русского языка может потребовать дополнительных ресурсов на не русскоязычной ОС, или вообще упасть с ошибкой, если какого-то пакета не хватает. Правильный подход именно такой.
- Предложено в качестве ответа Maksim MarinovMicrosoft contingent staff, Moderator 9 февраля 2021 г. 9:19
- Отменено предложение в качестве ответа Siompc 9 февраля 2021 г. 9:29
- Помечено в качестве ответа Siompc 10 февраля 2021 г. 19:12
9 февраля 2021 г. 3:34 -
Спасибо за помощь! Будем использовать полученные знания! :)9 февраля 2021 г. 9:29
-
Можно еще вопрос? Что бы использовать CultureInfo.InvariantCulture для преобразования числа, сервер тоже должен его отправлять в CultureInfo.InvariantCulture? Если сервер использует ru-RU, тогда ничего не получится?10 февраля 2021 г. 14:46
-
Попробуйте сами, и увидите, получиться или нет. InvariantCulture - это почти то же самое, что en-us, только для нее гарантируется, что она всегда доступна и ее параметры не зависят от настроек системы и обновлений. То есть для передачи данных по сети это как раз то, что нужно. С использованием другой культуры может получиться, но до поры до времени.
- Помечено в качестве ответа Siompc 10 февраля 2021 г. 21:18
10 февраля 2021 г. 16:40