2013-08-31 29 views
9

Chcę pobrać wartości dziesiętne z bazy danych i chciałbym wiedzieć, który jest zalecany sposób, aby sprawdzić wartości null.SqlDataReader Najlepszym sposobem sprawdzenia wartości null -sqlDataReader.IsDBNull vs DBNull.Value

Widziałem na MSDN - DBNull.Value Field, że ten czek jest rzadko używany.

Zatem, czy reader.IsDBNull jest najlepszym/najskuteczniejszym sposobem sprawdzania wartości zerowych?

Stworzyłem 2 metody próbkowania:

public static decimal? GetNullableDecimal(SqlDataReader reader, string fieldName) 
{ 
    if (reader[fieldName] == DBNull.Value) 
    { 
     return null; 
    } 
    return (decimal)reader[fieldName]; 
} 

public static decimal? GetNullableDecimal_2(SqlDataReader reader, string fieldName) 
{ 
    if (reader.IsDBNull(reader[fieldName])) 
    { 
     return null; 
    } 
    return (decimal)reader[fieldName]; 
} 

Większość czasu pola będą puste.

Z góry dziękuję!

+0

Którykolwiek wolisz i znajdziesz najbardziej czytelny. Warto jednak zauważyć, że twoje przykłady nie są dokładnie równoważne, biorąc pod uwagę użycie 'reader.GetOrdinal' w drugim. –

+1

Wewnętrznie składnia 'reader [nazwa pola]' została przetłumaczona na 'reader.GetOrdinal (fieldName)' – Steve

+0

Poprawiłem przykład użycia czytnika [fieldName] w obu przypadkach – diver

Odpowiedz

27

Nie byłbym zbyt pochłonięty tym, która metoda jest lepsza, ponieważ zarówno praca, jak i ja użyliśmy obu w kodzie wcześniej.

Na przykład, tutaj jest funkcja użyteczności ja wykopane z jednego z moich starych projektów:

/// <summary> 
/// Helper class for SqlDataReader, which allows for the calling code to retrieve a value in a generic fashion. 
/// </summary> 
public static class SqlReaderHelper 
{ 
    private static bool IsNullableType(Type theValueType) 
    { 
     return (theValueType.IsGenericType && theValueType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))); 
    } 

    /// <summary> 
    /// Returns the value, of type T, from the SqlDataReader, accounting for both generic and non-generic types. 
    /// </summary> 
    /// <typeparam name="T">T, type applied</typeparam> 
    /// <param name="theReader">The SqlDataReader object that queried the database</param> 
    /// <param name="theColumnName">The column of data to retrieve a value from</param> 
    /// <returns>T, type applied; default value of type if database value is null</returns> 
    public static T GetValue<T>(this SqlDataReader theReader, string theColumnName) 
    { 
     // Read the value out of the reader by string (column name); returns object 
     object theValue = theReader[theColumnName]; 

     // Cast to the generic type applied to this method (i.e. int?) 
     Type theValueType = typeof(T); 

     // Check for null value from the database 
     if (DBNull.Value != theValue) 
     { 
      // We have a null, do we have a nullable type for T? 
      if (!IsNullableType(theValueType)) 
      { 
       // No, this is not a nullable type so just change the value's type from object to T 
       return (T)Convert.ChangeType(theValue, theValueType); 
      } 
      else 
      { 
       // Yes, this is a nullable type so change the value's type from object to the underlying type of T 
       NullableConverter theNullableConverter = new NullableConverter(theValueType); 

       return (T)Convert.ChangeType(theValue, theNullableConverter.UnderlyingType); 
      } 
     } 

     // The value was null in the database, so return the default value for T; this will vary based on what T is (i.e. int has a default of 0) 
     return default(T); 
    } 
} 

Zastosowanie:

yourSqlReaderObject.GetValue<int?>("SOME_ID_COLUMN"); 
yourSqlReaderObject.GetValue<string>("SOME_VALUE_COLUMN"); 
+1

Awesome! Mam tylko jedną rekomendację, aby to zmienić. Zmień ten GetValue SqlDataReader na GetValue (ten IDataRecord – KevinDeus

6

Jeśli chcesz sprawdzić nieważną i obsługiwać go (jako w przeciwieństwie do sprawdzania wartości pustej i ostrzegania programu, że jest pusty) można użyć operatora as z operatorem zerowego koalescencyjnego ??. Więc w moim programie

SqlDataReader dr = cmd.ExecuteReader(); 
while (dr.Read()) 
{ 
    response.Employees.Add(new Employee() { Id = dr["id"] as int? ?? default(int), ImageUrl = dr["Photo"] as string, JobTitle = dr["JobTitle"] as string }); 
} 
+0

Schludny trik, dziękuję za udostępnienie! – Jocie

1

Oto prostsza wersja odpowiedzi @Karl Andersona:

public static class DbHelper 
{ 
    public static T GetValue<T>(this SqlDataReader sqlDataReader, string columnName) 
    { 
     var value = sqlDataReader[columnName]; 

     if (value != DBNull.Value) 
     { 
      return (T)value; 
     } 

     return default(T); 
    } 
} 

Albo nawet:

public static class DbHelper 
{ 
    public static T GetValue<T>(this SqlDataReader sqlDataReader, string columnName) 
    { 
     var value = sqlDataReader[columnName]; 

     return value == DBNull.Value ? default(T) : (T) value; 
    } 
} 

bezpośrednie odlewanie wydaje się działać dobrze dla obu pustych lub typy nieululujące.