SQL Data Reader - handling Null column values

前端 未结 27 2195
甜味超标
甜味超标 2020-11-22 08:53

I\'m using a SQLdatareader to build POCOs from a database. The code works except when it encounters a null value in the database. For example, if the FirstName column in the

相关标签:
27条回答
  • 2020-11-22 09:15

    One way to do it is to check for db nulls:

    employee.FirstName = (sqlreader.IsDBNull(indexFirstName) 
        ? ""
        : sqlreader.GetString(indexFirstName));
    
    0 讨论(0)
  • 2020-11-22 09:17

    There are a lot of answers here with useful info (and some wrong info) spread about, I'd like to bring it all together.

    The short answer to the question is to check for DBNull - almost everyone agrees on this bit :)

    Rather than using a helper method to read nullable values per SQL data type a generic method allows us to address this with a lot less code. However, you can't have a single generic method for both nullable value types and reference types, this is discussed at length in Nullable type as a generic parameter possible? and C# generic type constraint for everything nullable.

    So, following on from the answers from @ZXX and @getpsyched we end up with this, 2 methods for getting nullable values and I've added a 3rd for non-null values (it completes the set based on method naming).

    public static T? GetNullableValueType<T>(this SqlDataReader sqlDataReader, string columnName) where T : struct
    {
        int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
        return sqlDataReader.IsDBNull(columnOrdinal) ? (T?)null : sqlDataReader.GetFieldValue<T>(columnOrdinal);
    }
    
    public static T GetNullableReferenceType<T>(this SqlDataReader sqlDataReader, string columnName) where T : class
    {
        int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
        return sqlDataReader.IsDBNull(columnOrdinal) ? null : sqlDataReader.GetFieldValue<T>(columnOrdinal);
    }
    
    public static T GetNonNullValue<T>(this SqlDataReader sqlDataReader, string columnName)
    {
        int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
        return sqlDataReader.GetFieldValue<T>(columnOrdinal);
    }
    

    I usually use column names, alter these if you use column indexes. Based on these method names I can tell whether I'm expecting the data to be nullable or not, quite useful when looking at code written a long time ago.

    Tips;

    • Not having nullable columns in the database avoids this issue. If you have control over the database then columns should be non-null by default and only nullable where necessary.
    • Don't cast database values with the C# 'as' operator because if the cast is wrong it will silently return null.
    • Using a default value expression will change database nulls to non-null values for value types like int, datetime, bit etc.

    Lastly, whilst testing the above methods across all SQL Server data types I discovered you can't directly get a char[] from a SqlDataReader, if you want a char[] you will have to get a string and use ToCharArray().

    0 讨论(0)
  • 2020-11-22 09:17

    Convert handles DbNull sensibly.

    employee.FirstName = Convert.ToString(sqlreader.GetValue(indexFirstName));
    
    0 讨论(0)
  • 2020-11-22 09:18

    You can write a Generic function to check Null and include default value when it is NULL. Call this when reading Datareader

    public T CheckNull<T>(object obj)
            {
                return (obj == DBNull.Value ? default(T) : (T)obj);
            }
    

    When reading the Datareader use

                            while (dr.Read())
                            {
                                tblBPN_InTrRecon Bpn = new tblBPN_InTrRecon();
                                Bpn.BPN_Date = CheckNull<DateTime?>(dr["BPN_Date"]);
                                Bpn.Cust_Backorder_Qty = CheckNull<int?>(dr["Cust_Backorder_Qty"]);
                                Bpn.Cust_Min = CheckNull<int?>(dr["Cust_Min"]);
                             }
    
    0 讨论(0)
  • 2020-11-22 09:21

    neat one-liner:

        while (dataReader.Read())
    {
        employee.FirstName = (!dataReader.IsDBNull(dataReader.GetOrdinal("FirstName"))) ? dataReader["FirstName"].ToString() : "";
    }
    
    0 讨论(0)
  • 2020-11-22 09:23

    We use a series of static methods to pull all of the values out of our data readers. So in this case we'd be calling DBUtils.GetString(sqlreader(indexFirstName)) The benefit of creating static/shared methods is that you don't have to do the same checks over and over and over...

    The static method(s) would contain code to check for nulls (see other answers on this page).

    0 讨论(0)
提交回复
热议问题