简体   繁体   English

处理DBNull.Value

[英]Dealing with DBNull.Value

I frequently have to deal with DataTables connected to grid controls, custom updating always seems to produce a lot of code related to DBNull.Value. 我经常要处理连接到网格控件的DataTables,自定义更新似乎总会产生很多与DBNull.Value相关的代码。 I saw a similar question here but think there must be a better answer: 我在这里看到了类似的问题,但认为必须有一个更好的答案:

What is the best way to deal with DBNull's 处理DBNull的最佳方法是什么?

The thing I find is I tend to encapsulate my database updates in methods so I end up with code like below where I move the DBNull.value to a nullable type and then back for the update: 我找到的是我倾向于在方法中封装我的数据库更新,所以我最终得到如下代码,我将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
    }

That was just an example of the flow and not working code. 这只是流程的一个例子而不是工作代码。 I realize I could do things like pass objects or swallow potential casting problems using "as type" to get DBUll straight to null but both of these to me appear to hide potential errors, I like the type safety of the method with nullable types. 我意识到我可以做一些事情,比如传递对象或吞下潜在的投射问题,使用“as type”让DBUll直接为null但这两个对我来说似乎隐藏了潜在的错误,我喜欢具有可空类型的方法的类型安全性。

Is there a cleaner method to do this while maintaining type safety? 有没有更清洁的方法来保持类型安全?

A couple of (very) simple generic helper methods might at least concentrate the test into one piece of code: 一些(非常)简单的通用辅助方法可能至少将测试集中在一段代码中:

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;
}

These methods can then be used where appropriate: 然后可以在适当的地方使用这些方法:

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
}

I don't see what's wrong with as -casting and null coalescing. 我看不出有什么不对as -casting和null凝聚。

as -casting is used for reading: as -casting用于读取:

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

null coalescing is used for writing: null coalescing用于写入:

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

Both of these are completely typesafe and do not "hide" errors. 这两个都是完全类型安全的,不会“隐藏”错误。

If you really want, you can wrap these into static methods, so you end up with this for reading: 如果你真的想要,你可以将它们包装成静态方法,所以最后你可以阅读:

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

and this for writing: 这写作:

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

The static method code is slightly cleaner in the writing case, but the intent is less clear (especially in the reading case). 在写作情况下,静态方法代码稍微清晰一些,但意图不太明确(特别是在阅读案例中)。

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);
}

This is my implementation of DBNULL helper. 这是我对DBNULL帮助器的实现。 The usage is simple: 用法很简单:

new SqlParameter("Option1", option1.ToDbNullable())
parameters.Add("@requires_support", SqlDbType.Bit).Value = (object)requiresSupport ?? DBNull.Value;

which means the same as 这意味着相同

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

or 要么

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

(additional cast to object is required to remove the type ambiguity) (需要额外强制转换为对象以消除类型歧义)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM