DBNull在DotNet是单独的一个类型 System.DBNull 。它只有一个值 DBNull.Value 。
DBNull直接继承 Object ,所以 DBNull 不是 string , 不是 int , 也不是 DateTime 。。。
但是为什么 DBNull 可以表示数据库中的字符串,数字,或日期呢?原因是 DotNet 储存这些数据的类(DataRow 等)都是以 object 的形式来储存数据的。
对于 DataRow , 它的 row[column] 返回的值永远不为 null , 要么就是具体的为 column 的类型的值 。
要么就是 DBNull 。 所以 row[column].ToString()
这个写法永远不会在 ToString 那里发生 NullReferenceException。
DBNull 实现了 IConvertible 。 但是,除了 ToString 是正常的外,其他的 ToXXX 都会抛出不能转换的错误。
在 IDbCommand(OleDbCommand,SqlCommand...)
的 ExecuteScalar 的返回值中,情况可以这样分析:
select 1 这样返回的object是 1
select null 这样返回的是DBNull.Value
select isnull(null,1) 返回的是 1
select top 0 id from table1 这样返回的值是null
select isnull(id,0) from table1 where 1=0 返回的值是null
这里 ExecuteScalar 的规则就是,返回第一行第一列的数据。如果第一列第一行不为空,那么 ExecuteScalar 就直接对应的 DotNet 的值。如果有第一行,但是第一列为空,那么返回的是 DBNull 。如果一行都没有,那么 ExecuteScalar 就返回 null
规则就是这样的。这里容易犯的一个错误是,把 ExecuteScalar 返回 DBNull 与 null 的情况混淆,例如:
string username=cmd.ExecuteScalar().ToString();
除非你认为 cmd 执行后,肯定至少有一行数据,否则这里就会出错。
又或者 select id from usertable where username=@name
这样的 sql 语句,如果找不到记录,那么 ExecuteScalar 则会返回 null,所以千万不要
int userid=Convert.ToInt32(cmd.ExecuteScalar());
或者你会这样写 SQL 语句:select isnull(id,0) from usertable where
username=@name
但是 int userid=Convert.ToInt32(cmd.ExecuteScalar());
依然会出错,因为上面的语句不成立时,仍然是不返回任何行。
对于 IDbDataParameter(OleDDbParameter,SqlParameter..) 的 Value,如果为 null,则代表该参数没有指定,或者是代表 DEFAULT。如果为 DBNull.Value,则代表 SQL 中的 NULL
所以,如果你要调用存储过程,里面有参数 @val nvarchar(20)="AABB" ,
那么 cmd.Parameters["@val"].Value=null 代表使用这个默认的 "AABB"
而 cmd.Parameters["@val"].Value=DBNull.Value 代表使用 NULL 来传给 @val
你可以用 Convert.IsDBNull 来判断一个值是否 DBNull。注意 Convert.IsDBNull(null) 是 false。