對SqlParameter進行NULL賦值引發的錯誤

最近用C#在操作SqlParameter時發生一個詭異的錯誤,起源於我撰寫的類別中,有一個日期的欄位使用了System.Nullable<System.DateTime>的問題,而我直接將這個欄位直接導入到SqlParameter中的一個參數準備寫入,卻引發了SQL寫入的錯誤訊息。

未妥善處理Null引入到SqlParamter造成錯誤

該類別的時間日期欄位程式碼大概長得像這樣:

public System.DateTime? dBirthday { get; set; }

而在我的認知中,我認為只要引入這個類別實體的欄位,C#就會自動幫我轉換相關Null的相關處理。

oCmd.Parameters.Add("@dBirthday", System.Data.SqlDbType.DateTime).Value = oObj.dBirthday;

但是我錯了,當這個欄位是空值(Null)時,我從SQL端被踢回這樣的訊息:

SqlDateTime 溢位。必須在 1/1/1753 12:00:00 AM 和 12/31/9999 11:59:59 PM 之間。
SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.

正確將Nullable欄位透過SqlParameter寫入SQL的方式

答案是運用?? 運算子,來協助SqlParameter決定何時要取用哪樣的值,所以上述的程式碼應該改寫成下面這樣:

oCmd.Parameters.Add("@dBirthday", System.Data.SqlDbType.DateTime).Value = (System.Object)oObj.dBirthday ?? System.DBNull.Value;

透過上述的寫法,才可以正確地將System.Nullable<T>屬性的參數,正確的透過SqlParameter的方式寫入到SQL資料庫之中。

同場加映:正確將Nullable欄位從SQL讀取回物件欄位的方式

若要把資料從DataTable讀取回來,並塞入到物件的欄位之中,這時候使用上面的?? 運算子來解析是有難度的。在這裡我會建議改採用傳統的?:運算子來達成我們想要的功能,程式碼範例如下:

//可以寫成這樣
oObj.dBirthday = oItem.IsNull("dBirthday") ? (System.DateTime?)null : (System.DateTime)oItem["dBirthday"];
            
//亦可以寫成這樣(等效)
oObj.dBirthday = oItem.IsNull("dBirthday") ? (System.Nullable<System.DateTime>)null : (System.DateTime)oItem["dBirthday"];
SqlParameter AssignNullValue SendingNullValue PassNullValue System.Nullable