2010-08-17 15 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())