Published:
08 Nov 2007
|
Abstract
I see a lot on forums the question being asked about DBNull, and why it may cause problems when you read values from a reader, or try to assign it to a value type. This article delves into DBNull more explicitly and shows the differences between various objects. |
|
by Brian Mains
Feedback
|
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days):
33780/
54
|
|
|
Introduction |
The DBNull class is a special situation when it comes to
working with the ADO.NET framework, and even though it's mostly
straightforward, I still see a lot of confusion about how it can be used. So I
am writing this in hopes that this may alleviate someone's problems in the
future.
|
.NET Types |
The .NET Framework comes with many different types defined
within it. A type is a class, structure, or other declaration; for instance,
int, short, string, DataTable, List<string> are types, with the last one
being a generic type. The following code creates an instance of a type:
Listing 1
The variable I is of type int, and is an instance of the int
type with the value zero. There are two kinds of types; value types and
reference types. Reference types are defined as a class. For instance, the
following is a reference type:
Listing 2
MyClass is a reference type, which means it's stored on the
heap, and that it can be explicitly set to null. Some of the reference types
defined in the framework are: string, DataTable, DataSet, List<T>, and so
on. On the other hand, value types are defined as structures, but the value
types int, short, etc. inherit from the base class ValueType. The following is
a value type:
Listing 3
public struct MyValueType
{
}
Structures have certain rules, like they need to have at
least one field defined within it, as well as a few other rules. Some of the
common value types are: DateTime, Rectangle, int, short, long, and many more.
There are many articles on the web discussing the
differences between value and reference types. Please consult them for more
information.
|
Nullable Types |
Nullable types are a new feature to .NET 2.0, where they can
make any value type support null values. By defining a value type with a
question mark after it (in C#), or using the Nullable<T> class (in
VB.NET), the value type can support nulls simply by assigning null to it.
Nullable types add two additional members to it: the Value property and the
HasValue property. HasValue determines whether the nullable value actually has
a value, because if the Value property (which represents the actual value) is
accessed before being assigned a value, an exception is raised.
However, a nullable type is still an instance of the value
type (int? or Nullable(Of Int32)) is still a value of type int), and isn't
meant to represent or handle DBNull objects. Although when using the table
adapter feature of .NET 2.0 nullable types are used, they cannot handle DBNull,
because of what is described in the next section.
|
The DBNull Type |
When a value in the database is null in SQL Server or
Oracle, the equivalent to it an instance of the DBNull type. This type doesn't
match the type of a nullable value type, a reference type, or a value type, and
therefore is not directly assignable.
For instance, sometimes in code you will see items in a data
row being used without checking for null first. When the underlying field is
not null, this is OK, but if a null is available, the following code will not
work:
Listing 4
Decimal amount = (Decimal)row["AmountValue"]; //returned value is DBNull
Because DBNull is not the same type, an InvalidCastException
occurs. Rather, a null check has to be performed. The safe alternative to
this is the following:
Listing 5
Decimal amount = 0;
If (!row.IsNull("AmountValue"))
amount = (Decimal)row["AmountValue"];
If you want to set a row's value, you can do something like below.
The row takes an instance of type object, and therefore can be assigned DBNull:
Listing 6
If (amountValue > 0)
row["AmountValue"] = amountValue;
Else
row["AmountValue"] = DBNull.Value;
The value property returns the actual instance of DBNull (a
static property). Sometimes, a helper routine would be good to handle this
conversion for you, reducing the amount to a total of one line instead of
four. That may not seem like much, but a table with thirty columns will make
this much coding a chore.
|
Table Adapters |
Table adapters generate their own interface based on the
methods you create. For instance, if a table that has the fields ID, Name, and
Text, and the adapter generates the insert, update, and delete SQL statements,
the adapter will create overloaded Insert, Update, and Delete methods with these
fields as the parameters. However, you will notice that it will use nullable
type values for the value type parameters.
It may seem that a nullable type will be equivalent to
DBNull, but the table adapter transforms a nullable type to DBNull, when the
final execution is performed. The adapter has its own interface for doing so.
However, when using a table adapter to return a custom data table and rows,
there are special methods for determining if a field is null, and for setting
it to null. These methods are in the construct of Is<ColumnName>Null and
Set<ColumnName>Null. This handles using null values for particular
fields.
|
ADO.NET |
When working with ADO.NET, without a table adapter, to set a
row's value to null, use the DBNull.Value construct. This can also work with
command objects, when setting up the parameter. If you want to set a parameter
to null, simply assign DBNull.Value to the command's parameter definition, as
shown below:
Listing 7
Comand.Parameters.Add("@Field", SqlDbType.Varchar).Value = DBNull.Value
This translates to a null value in the database.
|
Conclusion |
DBNull is a special type that has to be handled carefully,
when working with various objects of the .NET 2.0 Framework. Take care when
reading/writing ADO.NET values because a null value could raise an
InvalidCastException.
|
|
|
User Comments
Title:
Nasty syntax for getting round this
Name:
Tyrannosaurs
Date:
2008-02-20 11:50:11 AM
Comment:
You cast a null date time to a dbnull like this:
datetime? myDateTime;
myDateTime = null;
.... parameters.add(...).value = (object)myDateTime ?? System.DBNull.Value;
It's pretty horrible but works and is no worse than most of the alternatives.
|
Title:
DBNULL
Name:
g
Date:
2007-11-19 6:37:19 AM
Comment:
this concept can be dealt in more detail
|
Title:
Datetime & DBNull Reply
Name:
Brian
Date:
2007-11-10 11:29:55 PM
Comment:
You can't cast directly; DBNULL and DateTIme are two separate object types, and you can't cast one to the other. However, in an ADO.NET datarow object, the underlying value is object, which could accept both. However, if the field is not null, then you can't assign a null value to it. It all depends on your code.
|
Title:
Datetime&DBnull
Name:
Erick
Date:
2007-11-09 6:49:21 AM
Comment:
When I assigned DBNull.Value to System.Datetime, it raised a exception. Can I set a Datetime field of the database to null by using DBNull.Value in ADO.net?
|
|
|
|