首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

深度解析 .NET 中 DBNull 與 Null 的本質差異

     編輯:關於SqlServer

核心結論:兩者屬於完全不同的型別體系

  • Null(null / Nothing / nullptr):CLR 參考型別的「無參考」狀態,表示變數未指向任何物件實例。
  • DBNull (System.DBNull):資料庫層面的「缺值」標記,是一個具體的單例類別(DBNull.Value),表示「此欄位不存在值」而非「值為空」。

混淆兩者是 ADO.NET 開發中最常見的 Bug 來源之一。

一、DBNull 類別深度剖析

  • 命名空間:System | 組件:mscorlib.dll
  • 單例模式:全域唯一實例 DBNull.Value,不可繼承、不可實例化。
  • 實作介面:IConvertible,但除 ToString() 外,所有 ToXxx() 均拋出 InvalidCastException。

二、資料庫與 .NET 的值對應關係

資料庫狀態SQL Server 表示ADO.NET 回傳.NET 對應
真正的 NULL(未輸入)NULL / <NULL>DBNull.ValueSystem.DBNull.Value
空字串(零長度)'' / 空白""String.Empty
數值型別無值NULLDBNull.ValueDBNull.Value

關鍵差異:Ctrl+0 在 SSMS 輸入真 NULL;清空儲存格輸入空字串。

三、ADO.NET 實戰防坑指南

1. ExecuteScalar 的三種回傳情境

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)。

2. 安全取值模式

// 錯誤:可能拋 NullReferenceException 或 InvalidCastException
int id = Convert.ToInt32(cmd.ExecuteScalar());

// 正確:分層防禦
object obj = cmd.ExecuteScalar();
int id = (obj == null || Convert.IsDBNull(obj)) ? 0 : Convert.ToInt32(obj);

3. DataRow 讀取最佳實務

// DataRow[index] 永不回傳 CLR null,只有 型別值 或 DBNull.Value
string name = row.IsNull("Name") ? "" : (string)row["Name"];  // 推薦
// 或
string name = row["Name"] as string ?? "";  // DBNull 不能 as string,會回傳 null

4. 參數傳遞:null vs DBNull.Value

// 儲存程序:@val NVARCHAR(20) = 'DEFAULT'
cmd.Parameters["@val"].Value = null;           // 使用 DEFAULT 值 'DEFAULT'
cmd.Parameters["@val"].Value = DBNull.Value;   // 傳遞 SQL NULL
cmd.Parameters["@val"].Value = "";             // 傳遞空字串

四、常見誤區速查表

誤區正確認知
"" == DBNull.ValueFalse。空字串 ≠ 資料庫 NULL
Convert.IsDBNull(null)回傳 False(null 是 CLR 無參考,非 DBNull)
row["col"].ToString() 安全安全(DBNull.ToString() 回傳 ""),但語意模糊
參數給 null 等於傳 NULL錯誤,null 代表「未指定參數/用預設值」

五、總結:三層防禦心法

  1. 認知層:Null = 參考缺失,DBNull = 資料庫缺值,兩者不可互換。
  2. 程式層:讀取時 IsNull / Convert.IsDBNull 雙重檢查;寫入參數時嚴格區分 null、DBNull.Value、""、0。
  3. 架構層:在 Repository/DAO 層封裝 SafeGet<T>(row, col, defaultVal) 統一處理,業務層只見強型別。

徹底釐清這兩個「空值」,能消除 80% 以上的 ADO.NET 執行期異常,也是資深 .NET 開發者的必修內功。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved