DBNull.Value),表示「此欄位不存在值」而非「值為空」。混淆兩者是 ADO.NET 開發中最常見的 Bug 來源之一。
System | 組件:mscorlib.dllDBNull.Value,不可繼承、不可實例化。IConvertible,但除 ToString() 外,所有 ToXxx() 均拋出 InvalidCastException。| 資料庫狀態 | SQL Server 表示 | ADO.NET 回傳 | .NET 對應 |
|---|---|---|---|
| 真正的 NULL(未輸入) | NULL / <NULL> | DBNull.Value | System.DBNull.Value |
| 空字串(零長度) | '' / 空白 | "" | String.Empty |
| 數值型別無值 | NULL | DBNull.Value | DBNull.Value |
關鍵差異:Ctrl+0 在 SSMS 輸入真 NULL;清空儲存格輸入空字串。
SELECT 1 → 1 (int)
SELECT NULL → DBNull.Value
SELECT TOP 0 id → null (CLR null,無資料列)
SELECT ISNULL(id,0) FROM t WHERE 1=0 → null (無資料列)
鐵律:先判 result == null(無列),再判 Convert.IsDBNull(result)(有列但值為 NULL)。
// 錯誤:可能拋 NullReferenceException 或 InvalidCastException
int id = Convert.ToInt32(cmd.ExecuteScalar());
// 正確:分層防禦
object obj = cmd.ExecuteScalar();
int id = (obj == null || Convert.IsDBNull(obj)) ? 0 : Convert.ToInt32(obj);
// DataRow[index] 永不回傳 CLR null,只有 型別值 或 DBNull.Value
string name = row.IsNull("Name") ? "" : (string)row["Name"]; // 推薦
// 或
string name = row["Name"] as string ?? ""; // DBNull 不能 as string,會回傳 null
// 儲存程序:@val NVARCHAR(20) = 'DEFAULT'
cmd.Parameters["@val"].Value = null; // 使用 DEFAULT 值 'DEFAULT'
cmd.Parameters["@val"].Value = DBNull.Value; // 傳遞 SQL NULL
cmd.Parameters["@val"].Value = ""; // 傳遞空字串
| 誤區 | 正確認知 |
|---|---|
"" == DBNull.Value | False。空字串 ≠ 資料庫 NULL |
Convert.IsDBNull(null) | 回傳 False(null 是 CLR 無參考,非 DBNull) |
row["col"].ToString() 安全 | 安全(DBNull.ToString() 回傳 ""),但語意模糊 |
參數給 null 等於傳 NULL | 錯誤,null 代表「未指定參數/用預設值」 |
IsNull / Convert.IsDBNull 雙重檢查;寫入參數時嚴格區分 null、DBNull.Value、""、0。SafeGet<T>(row, col, defaultVal) 統一處理,業務層只見強型別。徹底釐清這兩個「空值」,能消除 80% 以上的 ADO.NET 執行期異常,也是資深 .NET 開發者的必修內功。