InvalidCastException при использовании datareader.getString () в строковом поле, которое содержит числовое значение - PullRequest
0 голосов
/ 18 октября 2019

У меня есть поле в базе данных sqlite, мы назовем его field1, на котором я пытаюсь перебрать каждую запись (более тысячи записей). Тип поля string. Значение field1 в первых четырех строках выглядит следующим образом:

DEPARTMENT
09:40:24
PARAM
350297

Вот некоторый простой код, который я использую для перебора каждой строки и отображения значения:

while (sqlite_datareader.Read())
{
     strVal = sqlite_datareader.GetString(0);
     Console.WriteLine(strVal);
}

Первые 3 значения отображаются правильно. Однако, когда он достигает числовой записи 350297, он выдает ошибку, за исключением следующего метода .getString()

An unhandled exception of type 'System.InvalidCastException' occurred in System.Data.SQLite.dll

, который я пытался привести к строке и куче других вещей. Но я не могу понять, почему это происходит. Сейчас я вынужден использовать getValue типа object, а затем преобразовать обратно в строку. Но я хотел бы выяснить, почему getString() здесь не работает.

Есть идеи?

РЕДАКТИРОВАТЬ: Вот как я сейчас решаю проблему:

 object objVal;  // This is declared before the loop starts...

 objVal = sqlite_datareader.IsDBNull(i) ? "" : sqlite_datareader.GetValue(i);
 if (objVal != "")
 {
     strVal = (string)objVal;
 } 

1 Ответ

1 голос
/ 20 октября 2019

Вопрос должен был включать

  1. Схема таблицы, предпочтительно оператор CREATE TABLE, используемый для определения таблицы.
  2. Оператор SQL, используемый при открытии sqlite_datareader.

Каждый раз, когда вы сталкиваетесь с проблемами типов данных из базы данных, целесообразно включать такую ​​информацию. В противном случае возникает много ненужных догадок и ошибок (как видно из комментариев), когда очень полезная, критическая информация явно определяется в схеме DDL. Основной запрос для получения данных, возможно, менее критичен, но он вполне может быть частью проблемы, если есть операторы CAST и / или другие выражения, которые могут влиять на возвращаемые типы. Если бы я отлаживал проблему в моей собственной системе, это первое, что я бы проверил!


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

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

Но теперь рассмотрим ...

Столбец со сходством TEXT хранит все данные с использованием классов хранения NULL, TEXT или BLOB,Если числовые данные вставляются в столбец со сходством TEXT, перед сохранением они преобразуются в текстовую форму.

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

Но если вы прочитаете достаточно внимательно, вы в конце концов придете к следующему в конце раздела 3.1.1. Примеры имен сродства :

И объявленный тип "STRING" имеет сходство NUMERIC, а не TEXT.

Так что еслидетали вопроса взяты буквально, и field1 был определен как field1 STRING, тогда технически он имеет NUMERIC сходство и , так что значение типа 350297 было бы сохранено как целое число, а не строка . И поведение, описанное в этом вопросе, именно то, что можно ожидать при извлечении данных в строго типизированную модель данных, такую ​​как System.Data.SQLite.

Очень легко ругаться при таких не интуитивных дизайнерских решениях, и я не будузащитить поведение, но

  1. по крайней мере, результаты типа "STRING" четко указаны, так что столбец может быть переопределен в TEXT для решения проблемы, и
  2. "STRING "на самом деле не является стандартным типом данных SQL. Вместо этого строки SQL определяются с помощью TEXT, NTEXT, CHAR, NCHAR, VARCHAR, NVARCHAR и т. Д.

Решение состоит в том, чтобы использовать код в том виде, как он реализован в настоящее время: получить все значения какобъекты, а затем преобразовать в строковые значения ... что должно быть универсально возможным для объектов .Net, поскольку все они должны иметь определенный метод ToString().

Или переопределить столбец, чтобы иметь сходство с TEXT, например

CREATE TABLE myTable (
   ...
   field1 TEXT,
   ...
)

Точно, как переопределить существующий столбец, заполненный данными - это совсем другой вопрос. Однако, по крайней мере, когда вы выполняете преобразование из исходного в новый столбец, не забудьте использовать CAST(field1 AS TEXT), чтобы гарантировать, что класс хранения будет изменен для существующих данных. (Я не уверен, является ли соответствие типов "принудительным" при простом копировании / вставке данных из существующей таблицы в другую или исходный класс хранения сохраняется по умолчанию. Вот почему я предлагаю приведение, чтобы принудительно преобразовать его в текстовое значение. )

...