2015-10-30 2 views
1

У меня есть таблица с 2 столбцами (строка & int). Текущее значение для столбца int равно -1.Кастинг из исключения int to long throws

с помощью SQLDataReader Я чтения строк из этой таблицы:

public class MyObject 
{ 
    public string Name; 
    public long Number; 
} 

using (SqlDataReader dataReader = command.ExecuteReader()) 
{ 
    MyObject o = new MyObject() 
    while (dataReader.Read()) 
    { 
     o.Name= dataReader.GetString(0); 
     o.Number = dataReader.GetInt64(1); 
    } 
} 

Однако я получаю InvalidCastException при чтении Number колонки. Что мне здесь не хватает?

+0

Каков тип вашей второй колонки в db? И какая это ценность? –

+3

Не могли бы вы ввести дополнительную информацию: как схема для таблицы и команда, которую вы выполняете? – Lucian

+0

Можете ли вы опубликовать исключение? У него может быть больше информации. – nos

ответ

0

Хорошо сделать правильный вывод. Ваш столбцы DataType является ИНТ не BigInt так Вы не можете назвать это через .GetInt64(), потому что это является распакованный и

Вы не можете распаковывать Int32 -> Int64

Как @Adam Houldsworth упоминается -

"Прочитайте то, что дано, а не то, что вы хотите"

чтобы решить вашу проблему просто включите GetInt64() для GetInt32(). См. Ниже:

using (SqlDataReader dataReader = command.ExecuteReader()) 
{ 
    MyObject o = new MyObject() 
    while (dataReader.Read()) 
    { 
     o.Name= dataReader.GetString(0); 
     o.Number = dataReader.GetInt32(1); // safe implicitly cast no need to make it manually 
    } 
} 

Если вы не знаете точный базовый тип данных, вы всегда можете сделать это другим способом. Пожалуйста, см. Код ниже:

using (SqlDataReader dataReader = command.ExecuteReader()) 
{ 
    MyObject o = new MyObject() 
    while (dataReader.Read()) 
    { 
     o.Name = dataReader.GetString(0); 
     var number = dataReader.GetValue(1); 

     try 
     { 
      o.Number = Convert.ToInt64(number); 
     } 
     catch(InvalidCastException) 
     { 
      Throw new Exception("Underlying DataType is not convertable to int 64."); 
     } 
    } 
} 
5

Замечаний раздел SqlDataReader.GetInt64 гласит:

преобразование не выполняется; поэтому извлеченные данные уже должны быть 64-разрядным знаковым целым числом.

Кстати: не забудьте позвонить IsDBNUll, если ваше значение обнуляемым

Вы уверены, что полученные данные является BIGINT в вашей базе данных? если это ИНТ или NCHAR/NVARCHAR, вы должны использовать соответствующую функцию и бросание или разобрать его на System.Int64

Некоторые советы, чтобы улучшить надежность вашего кода

  • использование SqlDataReader [columnName] вместо GetInt64. Это даст вам объект в оригинальном типе, который, скорее всего, будет конвертирован в ваш длинный.
  • Использование имен столбцов вместо номеров столбцов повышает стабильность вашего кода. Он по-прежнему будет работать, если столбцы будут переупорядочены в вашем запросе или если добавлен или удален другой столбец из запроса
  • Если вы действительно хотите придерживаться функций GetInt ..., используйте SqlDataReader.GetOrdinal (имя столбца) для получите номер столбца.
  • Перед назначением использования SqlDataReader.GetFieldType проверить тип столбца и использовать соответствующий GetInt .. функцию
+0

True - я предлагаю OP попробовать с GetInt32 и посмотреть, что произойдет – MajkeloDev

+0

@MajkeloDev Он будет работать, поскольку это значение представляет собой 32-разрядное целое в действительности.Все это спорно так или иначе, потому что 'int' может неявно быть' long', без явного литья. –

+0

MajkeloDev: правда о том, что int кастинг длинный. Но внутри базы данных int не является int int в смысле того, чтобы быть четырехбайтным куском непрерывной памяти. SqlDataReader.GetInt32 предназначен для преобразования представления базы данных int, который официально скрыт в System.Int32, который может быть неявно передан в System.Int64 –

1

Вы должны прочитать его как int через GetInt32. Вам не нужно указывать его на long, потому что это может быть сделано неявно с безопасностью по времени выполнения.

Среда выполнение не позволит вам ип-бокса от object к другому типа данных без первого не-бокса object на правильный внутренний тип данных независимо от object есть, то приведение к следующему. Эта особенность не иметь ничего общего с читателями данных:

static void Main(string[] args) 
{ 
    int i = 1; 

    object o = i; 

    long l = (long)o; // invalid cast, trying to unbox to something other than the original type 

    l = (long)(int)o; // No invalid cast, un-boxed to int then cast to long. 
} 

В частности с SqlDataReader, потому что ваш базовый тип не Int64, он внутренне пытается не-поле непосредственно к неправильному типу:

internal Int64 Int64 { 
    get { 
     ThrowIfNull(); 

     if (StorageType.Int64 == _type) { 
      return _value._int64; 
     } 
     return (Int64)this.Value; // anything else we haven't thought of goes through boxing. 
    } 
    // set excluded for brevity 
} 

taken from http://referencesource.microsoft.com/#System.Data/System/Data/SqlClient/SqlBuffer.cs,1b180f5ee49fc7ee

TL; DR; Сделайте то, что говорится в документации (по рекомендации Харальддюца) и прочитайте правильный ожидаемый тип.

+0

Теперь я получаю вашу точку зрения и соглашаюсь с вами - это ошибка OP, которую он пытается вызвать методом GetInt64(), в то время как базовый тип DataType отличается (скорее всего). Метод GetInt64() пытается удалить значение внутри и исключить исключение. – MajkeloDev

+1

@MajkeloDev Да, я не очень хорошо себя зарекомендовал в первый раз, потому что я был ужален этим лет назад, и теперь по умолчанию я не пытаюсь это сделать, я всегда читаю то, что дается, а не то, что я хочу , Проблема с укоренившимся поведением заключается в том, что я не могу легко объяснить * почему * больше :-) –

+0

Я думаю, что этот вопрос может быть закрыт следующим заключением: «Читайте, что дано, а не то, что вы хотите» :) – MajkeloDev

0

Убедитесь, что значение, которое вы пытаетесь получить, это bigint в базе данных. BIGINT является эквивалентом Int64 (который длиннее на C#). Если его отличие от bigint пытается использовать Convert.ToInt64()

Смежные вопросы