10

グリッド コントロールに接続された DataTable を頻繁に処理する必要があります。カスタム更新では、常に DBNull.Value に関連する多くのコードが生成されるようです。ここで同様の質問を見ましたが、より良い答えがあるに違いないと思います:

DBNull に対処する最善の方法は何ですか?

私が見つけたのは、データベースの更新をメソッドにカプセル化する傾向があるため、DBNull.value を null 許容型に移動してから更新のために戻す以下のようなコードになります。

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
    }

これはフローの単なる例であり、コードは機能していません。オブジェクトを渡したり、「型として」を使用して潜在的なキャストの問題を飲み込んだりして、DBUll を直接 null にできることはわかっていますが、これらは両方とも潜在的なエラーを隠しているように見えます。null 許容型のメソッドの型安全性が気に入っています。

型の安全性を維持しながらこれを行うためのよりクリーンな方法はありますか?

4

4 に答える 4

17

いくつかの (非常に) 単純な汎用ヘルパー メソッドを使用すると、少なくともテストを 1 つのコードに集中させることができます。

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
}
于 2010-08-17T10:10:03.450 に答える
1

asキャストとnull合体の何が問題なのかわかりません。

as-キャストは読み取りに使用されます。

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

静的メソッドのコードは、書き込みの場合はわずかにきれいですが、意図はあまり明確ではありません (特に読み取りの場合)。

于 2010-08-17T12:35:49.153 に答える
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;

(型のあいまいさを取り除くには、オブジェクトへの追加のキャストが必要です)

于 2010-08-17T10:14:23.450 に答える
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())
于 2013-12-09T13:40:15.377 に答える