Say I have this class:
class myclass
{
public int Field1{ get; set; }
public int? Field2 { get; set; } //Note Field2 is nullable
}
I'm trying to populate a generic list with data coming from a database. As GetSqlInt32 implements INullable I would have thought that the below code would work. It doesn't. It generates an error if Field2 is null.
List<myclass> mylist=new List<myclass>();
int Field1_Ordinal = rdr.GetOrdinal("Field1");
int Field2_Ordinal = rdr.GetOrdinal("Field2");
SqlDataReader rdr = cmd.ExecuteReader(); //Execute a stored procedure to retrieve data from the database
while (rdr.Read())
{
mylist.Add(new myclass
{
Field1 = rdr.GetSqlInt32(Field1_Ordinal).Value,
Field2 = rdr.GetSqlInt32(Field2_Ordinal).Value //Error if field2 is null
});
}
Any ideas why it doesn't work?
Handling Null column values using turnery operator: In this example I used turnery operator with DBNull. Value to check sql data reader columns value is null or not, if found null then column value assigned to some default value.
GetValue(0) != DbNull. Value) //if value in columnA is not null { //.... } }
The NULL value can cause problems when selecting data. However, because when comparing an unknown value to any other value, the result is always unknown and not included in the results. You must use the IS NULL or IS NOT NULL operators to check for a NULL value.
For working with database ANSI SQL null values, use System. Data. SqlTypes nulls rather than Nullable. For more information on working with CLR value nullable types in Visual Basic see Nullable Value Types, and for C# see Nullable value types.
It seems to me that you need a conversion like this (using an extension method for convenience):
public static int? ToNullableInt32(this SqlInt32 value)
{
return value.IsNull ? (int?) null : value.Value;
}
Then:
Field2 = rdr.GetSqlInt32(Field2_Ordinal).ToNullableInt32()
(Comment on other answers: there's no need to bring DbNull
into this, as SqlInt32
can already represent null values. You just need to detect that before using Value
.)
Check out this solution which wasn't written by me:
employee.FirstName = sqlreader[indexFirstName] as string;
employee.Age = sqlreader[indexAge] as int? ?? default(int);
It was originally proposed here:
SQL Data Reader - handling Null column values
Here's a pain reduction variation on the theme. If someone knows how to merge Val and Ref into one template function fell free to post. You will have to state the type explicitly (C# compiled can't be bothered :-) but this:
var dd = r.Val<DateTime>(ords[4]);
var ii = r.Def<int>(ords[0]);
int nn = r.Def<int>(ords[0]);
is still maked my fingers happy :-)
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;
}
I think it is beacuse the value returned is DBNull.Value
, and not null
.
Instead you can use the IsDbNull() method to check if the field is null before reading it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With