SqlDataReader возвращает пустое значение вместо null для поля типа int

Я использую SqlDataReader для извлечения данных из базы данных SQL Server 2012:

SqlConnection connection = (SqlConnection)_db.Database.GetDbConnection();
await connection.OpenAsync();
SqlCommand command = new SqlCommand("dbo.[sp_MyStoredPrc] @InputId=1", connection);
var reader = await command.ExecuteReaderAsync();

if (reader.HasRows)
{
    while (reader.Read())
    {
        int? var1 = (int?)reader["Column1Name"];
    }
}

При чтении поля NULL int из базы данных reader["Column1Name"] пусто, поэтому код генерирует исключение InvalidCastException во время выполнения.

я пытался

reader.GetInt32(reader.GetOrdinal("Column1Name"))

но это вызывает исключение System.Data.SqlTypes.SqlNullValueException.

Я тоже пробовал

reader.GetSqlInt32(reader.GetOrdinal("Column1Name"))

который возвращает null, но тип SqlInt32, а не int?, как я хочу.

Я закончил делать

if (!reader.IsDBNull(reader.GetOrdinal("Column1Name"))) 
    int? var1 = (int?)reader["Column1Name"];

который работает.

Вопросы:

  1. Нет ли более простого способа, чем вызвать метод IsDBNull?

  2. Почему reader["Column1Name"] возвращает пустое значение вместо null, если значение db равно NULL, а поле - int?


person dfmetro    schedule 21.01.2016    source источник
comment
Я не уверен, но попробуйте использовать Convert.ToInt32 (reader [Column1Name]);   -  person SergeyAn    schedule 21.01.2016
comment
Я получаю исключение, потому что Reader [Column1Name] пуст   -  person dfmetro    schedule 21.01.2016
comment
Вы уверены, что значение db равно нулю? Оно может быть пустым, но это не значит, что оно пустое. В противном случае нет простого способа справиться с этим, чем проверить пустое значение.   -  person SergeyAn    schedule 21.01.2016
comment
Я уверен, что это ноль. Я могу выполнить трассировку профилировщика SQL, чтобы увидеть, что ti возвращает ноль. Также reader.GetSqlInt32 (reader.GetOrdinal (Column1Name)) возвращает null   -  person dfmetro    schedule 21.01.2016
comment
Спасибо за разъяснение. Кроме того, Column1Name и ColumnName1 - это разные поля?   -  person SergeyAn    schedule 21.01.2016
comment
Хороший вопрос! С другой стороны, я лично использую подход, описанный в ответе. Он показывает, как читать общую информацию, возвращаемую от читателя в List<dynamic>. Таким же образом можно сохранить результаты в List<Dictionary<string, object>>. В результате можно читать данные и нет проблем с чтением null, потому что вы читаете данные по порядковому номеру.   -  person Oleg    schedule 21.01.2016


Ответы (2)


Почему reader["Column1Name"] возвращает пустое значение вместо нуля, если значение db равно нулю, а поле - int?

Фактически, reader["Column1Name"] возвращает DBNull.Value, если значение базы данных NULL. (В отладчике Visual Studio значение кажется пустым, потому что DBNull.ToString () возвращает пустую строку.) Вы не можете преобразовать DBNull.Value напрямую в int? с помощью оператора приведения.

Нет ли более простого способа вызвать метод IsDBNull?

Да, используйте оператор as вместо приведения:

int? var1 = reader["Column1Name"] as int?;

Поскольку DBNull.Value не является int, оператор as возвращает null.

person Michael Liu    schedule 21.01.2016

C # не может преобразовать строку в int? используя (int?). Самый безопасный способ - использовать условный оператор для проверки на null, а затем вручную установить значение null.

//Get the column index to prevent calling GetOrdinal twice
int COLUMNNAME1 = reader.GetOrdinal("ColumnName1");

while (reader.Read())
{
    int? var1 = reader.IsDBNull(COLUMNNAME1) ? null : reader.GetInt32(COLUMNNAME1);
}

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

int STRINGCOLUMN = reader.GetOrdinal("StringColumn");
int INTCOLUMN = reader.GetOrdinal("IntColumn");
int DATECOLUMN = reader.GetOrdinal("DateColumn");
int BOOLCOLUMN = reader.GetOrdinal("BoolColumn");

while (reader.Read())
{
    string var1 = reader.IsDBNull(STRINGCOLUMN) ? "" : reader.GetString(STRINGCOLUMN);
    int var2 = reader.IsDBNull(INTCOLUMN) ? 0 : reader.GetInt32(INTCOLUMN);
    DateTime var3 = reader.IsDBNull(DATECOLUMN) ? DateTime.MinValue : reader.GetDateTime(DATECOLUMN);
    bool var4 = reader.IsDBNull(BOOLCOLUMN) ? false : reader.GetBoolean(BOOLCOLUMN);
}
person Will Parks    schedule 21.01.2016