2010-08-17 46 views
10

我經常需要處理連接到網格控件的DataTables,自定義更新似乎總是會產生大量與DBNull.Value相關的代碼。我看到了一個類似的問題在這裏,但認爲必須有一個更好的答案:處理DBNull.Value

What is the best way to deal with DBNull's

,我覺得是我傾向於用各種方法封裝我的數據庫更新,所以我結束了類似下面的代碼,我移動的東西DBNull.value到可空類型,然後再進行更新:

private void UpdateRowEventHandler(object sender, EventArgs e) 
{ 
    Boolean? requiresSupport = null; 
    if (grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport) != DBNull.Value) 
     requiresSupport = (bool)grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport); 

    AdditionalSupport.UpdateASRecord(year, studentID, requiresSupport) 
} 

internal static void UpdateASRecord(
     string year, 
     string studentID,    
     bool? requiresSupport) 
    { 
     List<SqlParameter> parameters = new List<SqlParameter>(); 

     parameters.Add(new SqlParameter("@year", SqlDbType.Char, 4) { Value = year }); 
     parameters.Add(new SqlParameter("@student_id", SqlDbType.Char, 11) { Value = studentID }); 

     if (requiresSupport == null) 
      parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) { Value = DBNull.Value }); 
     else 
      parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) { Value = requiresSupport }); 

     //execute sql query here to do update 
    } 

這只是流動的一個例子,而不是工作的代碼。我意識到我可以使用「as type」來執行諸如傳遞對象或吞噬潛在的投射問題之類的事情,以使DBUll直接爲null,但這兩個對我來說似乎隱藏了潛在的錯誤,我喜歡使用可爲空類型的方法的類型安全性。

有沒有一種更乾淨的方法來做到這一點,同時保持類型安全?

+0

爲什麼不直接使用強類型的DataRow?你提到你必須使用DataTables。如果這些數據表是強類型的,您可以將數據行發送到您的方法。數據行已經使用DBNull。 – 2010-08-17 10:57:38

回答

14

一對夫婦的非常簡單的通用輔助方法可能測試至少集中成一體的代碼:然後

static T FromDB<T>(object value) 
{ 
    return value == DBNull.Value ? default(T) : (T)value; 
} 

static object ToDB<T>(T value) 
{ 
    return value == null ? (object) DBNull.Value : value; 
} 

可以使用這些方法在適當情況下:

private void UpdateRowEventHandler(object sender, EventArgs e) 
{ 
    AdditionalSupport.UpdateASRecord(year, studentID, 
     FromDB<Boolean?>(grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport))); 
} 

internal static void UpdateASRecord(
     string year, 
     string studentID, 
     bool? requiresSupport) 
{ 
    List<SqlParameter> parameters = new List<SqlParameter>(); 

    parameters.Add(new SqlParameter("@year", SqlDbType.Char, 4) { Value = year }); 
    parameters.Add(new SqlParameter("@student_id", SqlDbType.Char, 11) { Value = studentID }); 
    parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) { Value = ToDB(requiresSupport) }); 

    //execute sql query here to do update 
} 
+2

建議使用'Convert.IsDBNull()'而不是'value == DBNull.Value'。可能是'FromDBNull' /'ToDBNull'而不僅僅是FromDB' /'ToDB'。 – abatishchev 2010-08-17 10:20:48

+0

這看起來更整潔,謝謝我認爲泛型可能是一種方式,除非有人提出更好的解決方案,否則我會使用它。 – PeteT 2010-08-17 10:34:18

+1

@abatishchev:是的,使用'Convert.IsDBNull'可能會更優雅;封裝測試本身並不是該方法的目的。關於命名,我可以同意'FromDB'和'ToDB'有一點差距,儘管我寧願調用方法'ToDBValue'和'FromDBValue',因爲它們不會將所有值轉換爲'DBNull',但而是以傳遞給數據庫或從數據庫獲取的形式返回傳遞的值。 – 2010-08-17 10:40:31

0
parameters.Add("@requires_support", SqlDbType.Bit).Value = (object)requiresSupport ?? DBNull.Value; 

表示與

相同
parameters.Add("@requires_support", SqlDbType.Bit).Value = (requiresSupport != null) ? (object)requiresSupport : DBNull.Value; 

if (requiresSupport != null) 
    parameters.Add("@requires_support", SqlDbType.Bit).Value = requiresSupport 
else 
    parameters.Add("@requires_support", SqlDbType.Bit).Value = DBNull.Value; 

(需要對象附加投去除型歧義)

+0

@ petebob796:我的解決方案是最浪潮的,不是嗎? – abatishchev 2010-08-17 11:02:54

1

我看不出這有什麼錯as -casting和null凝聚。

as -casting用於讀取:

bool? requiresSupport = 
    grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport) as bool?; 
AdditionalSupport.UpdateASRecord(year, studentID, requiresSupport); 

null凝聚用於書寫:

parameters.Add(new SqlParameter("@student_id", SqlDbType.Char, 11) 
    { Value = studentID }); 
parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) 
    { Value = (object)requiresSupport ?? DBNull.Value }); 

這些都完全是類型安全的也不要 「隱藏」 的錯誤。

如果你真的想要,你可以包裝到這些靜態的方法,讓你結束了這個閱讀:

//bool? requiresSupport = 
// grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport) as bool?; 
bool? requiresSupport = FromDBValue<bool?>(
    grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport)); 

這對於寫作:

//parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) 
// { Value = (object)requiresSupport ?? DBNull.Value }); 
parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) 
    { Value = ToDBValue(requiresSupport) }); 

靜態方法代碼在寫作案例中略顯清晰,但意圖不太清晰(特別是在閱讀案例中)。

0
public static object DbNullable<T>(T? value) where T : struct 
{ 
    if (value.HasValue) 
    { 
     return value.Value; 
    } 
    return DBNull.Value; 
} 

public static object ToDbNullable<T>(this T? value) where T : struct 
{ 
    return DbNullable(value); 
} 

這是我執行的DBNULL幫手。用法很簡單:

new SqlParameter("Option1", option1.ToDbNullable())