views:

1398

answers:

9

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 database contains a null value, an exception is thrown.

employee.FirstName = sqlreader.GetString(indexFirstName);

What is the best way to handle null values in this situation?

+4  A: 

You need to check for IsDBNull:

if(!SqlReader.IsDBNull(indexFirstName))
{
  employee.FirstName = sqlreader.GetString(indexFirstName);
}

That's your only reliable way to detect and handle this situation.

I wrapped those things into extension methods and tend to return a default value if the column is indeed NULL:

public static string SafeGetString(this SqlDataReader reader, int colIndex)
{
   if(!reader.IsDBNull(colIndex))
       return reader.GetString(colIndex);
   else 
       return string.Empty;
}

Now you can call it like this:

employee.FirstName = SqlReader.SafeGetString(indexFirstName);

and you'll never have to worry about an exception or a NULL value again.

marc_s
User error! This is what I was trying but screwed it up. I was making it too complicated, All is good now. Thanks.
Scott
A: 

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

employee.FirstName = (sqlreader.IsDBNull(indexFirstName) 
    ? ""
    : sqlreader.GetString(indexFirstName));
Michael Todd
I don't think this check will work - you need to use sqlreader.IsDBNull(indexFirstName)
marc_s
Oops, you're right. Thanks.
Michael Todd
@Michael: the "IsDBNull" returns a boolean - true or false - you can't compare the result of IsDBNull against DBNull.Value.....
marc_s
(hanging head) Riiiiight....methinks checking my code against a compiler is in order.
Michael Todd
Thanks, Marc. I appreciate your assistance in setting my code straight.
Michael Todd
A: 

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).

Sonny Boy
+2  A: 

What I tend to do is replace the null values in the SELECT statement with something appropriate.

SELECT ISNULL(firstname, '') FROM people

Here I replace every null with a blank string. Your code won't throw in error in that case.

alex
If possible, use this avoid nulls. Otherwise, I like Sonny Boy's answer of helper methods.
No Refunds No Returns
Why a static, separate helper method? Doesn't an extension method on the SqlDataReader seem more compelling and more intuitive??
marc_s
A: 

and / or use ternary operator with assignment:

employee.FirstName = rdr.IsNull(indexFirstName))? 
                     String.Empty: rdr.GetString(indexFirstName);

replace the default (when null) value as appropriate for each property type...

Charles Bretana
+1  A: 

Check sqlreader.IsDBNull(indexFirstName) before you try to read it.

CesarGon
+1  A: 

I think you would want to use:

SqlReader.IsDBNull(indexFirstName)
J.13.L
+1  A: 

IsDbNull(int) is usually much slower that using methods like Get*Sql*DateTime and then comparing to DBNull.Value. Try these extension methods for SqlDataReader. Use then like:

var dd = r.Val<DateTime>(ords[4]);
var ii = r.Def<int>(ords[0]);
int nn = r.Def<int>(ords[0]);

public static T Def<T>(this SqlDataReader r, int ord)
{
    var t = r.GetSqlValue(ord);
    if (t == DBNull.Value) return default(T);
    return ((INullable)t).IsNull ? default(T) : (T)t;
}

public static T? Val<T>(this SqlDataReader r, int ord) where T:struct
{
    var t = r.GetSqlValue(ord);
    if (t == DBNull.Value) return null;
    return ((INullable)t).IsNull ? (T?)null : (T)t;
}

public static T Ref<T>(this SqlDataReader r, int ord) where T : class
{
    var t = r.GetSqlValue(ord);
    if (t == DBNull.Value) return null;
    return ((INullable)t).IsNull ? null : (T)t;
}
ZXX
+2  A: 

You should use the as operator combined with the ?? operator for default values. Value types will need to be read as nullable and given a default.

employee.FirstName = sqlreader[indexFirstName] as string;
employee.Age = sqlreader[indexAge] as int? ?? default(int);

The as operator handles the casting including the check for DBNull.

Stevo3000
+1 This is the exact syntax I use - I just love how elegant it is
MPritch