I frequently have problems dealing with DataRows
returned from SqlDataAdapters
. When I try to fill in an object using code like this:
DBNull implements .ToString() like everything else. No need to do anything. Instead of the hard cast, call the object's .ToString() method.
DataRow row = ds.Tables[0].Rows[0];
string value;
if (row["fooColumn"] == DBNull.Value)
{
value = string.Empty;
}
else
{
value = Convert.ToString(row["fooColumn"]);
}
this becomes:
DataRow row = ds.Tables[0].Rows[0];
string value = row.ToString()
DBNull.ToString() returns string.Empty
I would imagine this is the best practice you're looking for
If you are concerned with getting DBNull when expecting strings, one option is to convert all the DBNull values in the DataTable into empty string.
It is quite simple to do it but it would add some overhead especially if you are dealing with large DataTables. Check this link that shows how to do it if you are interested
I usually write my own ConvertDBNull class that wraps the built-in Convert class. If the value is DBNull it will return null if its a reference type or the default value if its a value type.
Example:
- ConvertDBNull.ToInt64(object obj)
returns Convert.ToInt64(obj)
unless obj is DBNull in which case it will return 0.
Nullable types are good, but only for types that are not nullable to begin with.
To make a type "nullable" append a question mark to the type, for example:
int? value = 5;
I would also recommend using the "as
" keyword instead of casting. You can only use the "as" keyword on nullable types, so make sure you're casting things that are already nullable (like strings) or you use nullable types as mentioned above. The reasoning for this is
as
" keyword returns null
if a value is DBNull
.as
, but coupled with the reason above it's useful.I'd recommend doing something like this
DataRow row = ds.Tables[0].Rows[0];
string value = row as string;
In the case above, if row
comes back as DBNull
, then value
will become null
instead of throwing an exception. Be aware that if your DB query changes the columns/types being returned, using as
will cause your code to silently fail and make values simple null
instead of throwing the appropriate exception when incorrect data is returned so it is recommended that you have tests in place to validate your queries in other ways to ensure data integrity as your codebase evolves.
I always found it clear, concise, and problem free using a version of the If/Else check, only with the ternary operator. Keeps everything on one row, including assigning a default value if the column is null.
So, assuming a nullable Int32 column named "MyCol", where we want to return -99 if the column is null, but return the integer value if the column is not null:
return row["MyCol"] == DBNull.Value ? -99 : Convert.ToInt32(Row["MyCol"]);
It is the same method as the If/Else winner above - But I've found if you're reading multiple columns in from a datareader, it's a real bonus having all the column-read lines one under another, lined up, as it's easier to spot errors:
Object.ID = DataReader["ID"] == DBNull.Value ? -99 : Convert.ToInt32(DataReader["ID"]);
Object.Name = DataReader["Name"] == DBNull.Value ? "None" : Convert.ToString(DataReader["Name"]);
Object.Price = DataReader["Price"] == DBNull.Value ? 0.0 : Convert.ToFloat(DataReader["Price"]);
Often when working with DataTables you have to deal with this cases, where the row field can be either null or DBNull, normally I deal with that like this:
string myValue = (myDataTable.Rows[i]["MyDbNullableField"] as string) ?? string.Empty;
The 'as' operator returns null for invalid cast's, like DBNull to string, and the '??' returns the term to the right of the expression if the first is null.