Объект не может быть приведен из DBNull к другим типам. Ошибка, когда читатель читает нулевое значение - PullRequest
8 голосов
/ 03 ноября 2011
int topID = 0;
string TopIDQuery = "Select TopID from tbl_Organisation where OrganisationID=@OrgID";

paramet[0] = new MySqlParameter("@OrgID", MySqlDbType.Int32);
paramet[0].Value = OrgID;

reader = server.ExecuteReader(CommandType.Text, TopIDQuery, paramet);

while (reader.Read())
{
    topID = Convert.ToInt32(reader["TopID"]);
}

reader.Close();

Я читаю topID из таблицы, когда TopID равно нулю, я хочу оставить topID как 0, но, поскольку оно равно нулю, оно выдает ошибку, как я могу обработать эту ошибку, когда topID равно нулю

Ответы [ 8 ]

6 голосов
/ 03 ноября 2011

Измените код чтения на:

while (reader.Read())
{
    if(reader.IsDBNull(reader.GetOrdinal("TopID")))
       topID = 0;
    else
       topID = Convert.ToInt32(reader["TopID"]);
}
4 голосов
/ 03 ноября 2011

Вызовите IsDBNull() на считывателе, чтобы проверить столбец, прежде чем пытаться преобразовать его:

   using (reader = server.ExecuteReader(CommandType.Text, TopIDQuery, paramet))
   {
       while (reader.Read())
       {
           var column = reader.GetOrdinal("TopID");

           if (!reader.IsDBNull(column))
              topID = Convert.ToInt32(reader[column]);
           }
       }
   }

Или сравните с DBNull.Value:

   var value = reader["TopID"];

   if (value != DBNull.Value)
   {
       topID = Convert.ToInt32(value);
   }
1 голос
/ 03 ноября 2011

Проблема в том, что вы пытаетесь установить int с нулем, а не в чтении.Вы можете сделать это, чтобы установить альтернативное значение, если значение, которое вы пытаетесь вставить, равно NULL:

    topID = Convert.ToInt32(reader["TopID"]) ?? 0;

Другой альтернативой является то, что вы можете использовать целые числа, допускающие значение NULL, путем инициализации topID следующим образом:

int? topID = 0

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

1 голос
/ 03 ноября 2011

Используйте тест:

int columnNr = reader.GetOrdinal("TopID");
if (!reader.IsDBNull(columnNr)) {
    topID =  reader.GetInt32(columnNr);
}
0 голосов
/ 03 сентября 2016

Используйте универсальный метод расширения для вашего читателя (см. Аналогичный SO вопрос )

topID = reader.GetFieldValueOrDefaultIfDBNull<Int32>("TopID");

Реализуйте этот метод расширения в своем классе читателя (MySql, Sql, Oracle и т. Д.)

public static T GetFieldValueOrDefaultIfDBNull<T>(this SqlDataReader reader, string indexName)
{
    if (reader.IsDBNull(reader.GetOrdinal(indexName)))
    {
        return default(T); // returns the default value for the type
    }
    else
    {
        return reader.GetFieldValue<T>(reader.GetOrdinal(indexName));
    }
}
0 голосов
/ 16 апреля 2014

Вот код, в котором мы автоматически генерируем любой идентификатор из базы данных MS Access при загрузке страницы любой регистрационной формы

void Number()
{
    con.Open();
    int id;
    cmd = new OleDbCommand("select max(ID) from Entry", con);
    string value = (cmd.ExecuteScalar().ToString());
    string max;
    if (value != null)
    {      
        max = "0"+value;
        id = Convert.ToInt32(max);
        lblNumber.Text = "Acronym of Reg form like for Emp for Employee" 
                        + Convert.ToString((id + 1));

    }
    con.Close();
}
0 голосов
/ 03 ноября 2011

Мне нравится использовать DataTable вместо DataReader. Я ненавижу повторяющиеся шаблоны, поэтому я добавил некоторые методы расширения в класс DataRow, чтобы инкапсулировать нисходящую логику и сделать код более читабельным:

DataTable dt = ExecStoredProcedure() ;
foreach ( DataRow dr in dt )
{
  int       id            = dr.CastAsInt("id") ;
  dateTime? dtLastUpdated = dr.CastAsDateTimeNullable("last_update_date") ;
  int?      col3          = dr.CastASIntNullable(3) ;
}

Здесь код для уменьшения значения столбца от DataRow до int / int?:

#region downcast to int

public static int CastAsInt( this DataRow row , int index )
{
    return toInt( row[index] ) ;
}
public static int CastAsInt( this DataRow row , string columnName )
{
    return toInt( row[columnName] ) ;
}

public static int? CastAsIntNullable( this DataRow row , int index )
{
    return toIntNullable( row[index] );
}
public static int? CastAsIntNullable( this DataRow row , string columnName )
{
    return toIntNullable( row[columnName] ) ;
}

#region conversion helpers

private static int toInt( object o )
{
    int value = (int)o;
    return value;
}

private static int? toIntNullable( object o )
{
    bool hasValue = !( o is DBNull );
    int? value    = ( hasValue ? (int?) o : (int?) null ) ;
    return value;
}

#endregion conversion helpers

#endregion downcast to int

Я уверен, что повесить подобные методы расширения на DataReader было бы довольно просто.

0 голосов
/ 03 ноября 2011

Вам нужно проверить, является ли значение DBNull, прежде чем пытаться получить его.Кроме того, я рекомендую использовать GetInt32() сверх Convert.ToInt32(), поскольку было заявлено, что внутренняя оптимизация GetInt32() может измениться, где она будет быстрее, чем при использовании Convert.ToInt32().Я узнал об этом давным-давно, и у меня нет справочной статьи, на которую вы могли бы взглянуть.В то время, когда я узнал, что GetInt32() внутренне использовал Convert.ToInt32()

while(reader.Read()) {
    int TopIDIndex = reader.GetOrdinal("TopID");
    topID = reader.IsDBNull(TopIDIndex)
        ? 0
        : reader.GetInt32(TopIDIndex);
}
...