C#ADO.NET:nullとDbNull—より効率的な構文はありますか?
質問
DbParameter
を使用してフィールドに挿入しようとしている DateTime?
があります。次のようにパラメーターを作成しています:
DbParameter datePrm = updateStmt.CreateParameter();
datePrm.ParameterName = "@change_date";
そして、 null
を考慮しながら、 DateTime?
の値を dataPrm.Value
に入れます。
最初は賢いと思いました:
datePrm.Value = nullableDate ?? DBNull.Value;
しかし、エラーで失敗します
演算子 '??' 「System.DateTime?」タイプのオペランドには適用できませんおよび「System.DBNull」
したがって、2番目の引数が最初の引数のnull不可バージョンである場合にのみ機能すると思います。それで私は行きました:
datePrm.Value = nullableDate.HasValue ? nullableDate.Value : DBNull.Value;
しかし、それも機能しません:
「System.DateTime」と「System.DBNull」の間に暗黙的な変換がないため、条件式のタイプを判別できません
しかし、これらの型の間で変換したくない!
これまでのところ、私が働くことができるのは次のとおりです。
if (nullableDate.HasValue)
datePrm.Value = nullableDate.Value;
else
datePrm.Value = DBNull.Value;
これが本当にこれを書く唯一の方法ですか?三項演算子を使用してワンライナーを動作させる方法はありますか?
更新:なぜ??バージョンが機能しません。 MSDNによると:
??演算子は、nullでない場合は左側のオペランドを返し、そうでない場合は右側のオペランドを返します。
まさにそれが私が欲しいものです!
Update2:それは最後に明らかになった:
datePrm.Value = nullableDate ?? (object)DBNull.Value;
解決
あはは! @Trebzのソリューションよりもさらに効率的なソリューションを見つけました!
datePrm.Value = nullableDate ?? (object)DBNull.Value;
他のヒント
SQLServerを使用している場合、 System.Data.SqlTypes
名前空間には、迷惑な型キャストを回避するユーティリティクラスが含まれています。たとえば、これの代わりに:
var val = (object) "abc" ?? DBNull.Value;
これを書くことができます:
var val = "abc" ?? SqlString.Null;
使用すると機能します
datePrm.Value = nullableDate.HasValue ? (object)nullableDate.Value : DBNull.Value;
C#3.0を使用している場合、拡張メソッドを作成してこれを簡単に行うことができます。
public static class DBNullableExtensions
{
public static object ToDBValue<T>(this Nullable<T> value) where T:struct
{
return value.HasValue ? (object)value.Value : DBNull.Value;
}
}
class Program
{
static void Main(string[] args)
{
int? x = null;
Console.WriteLine( x.ToDBValue() == DBNull.Value );
}
}
2回目の試行でのエラーは、nullableDate.ValueとDBNull.Valueが異なるタイプであり、三項演算子が両方の場合に1つのタイプを選択する必要があるためだと思います。これをテストする環境はありませんが、これはあなたに役立つはずだと思います:
datePrm.Value = nullableDate.HasValue ? (object)nullableDate.Value : (object)DBNull.Value;
その方法は、パラメータ値がnullであるかどうかを確認してから、DBNullを実行するように値を設定する静的ユーティリティクラスがあることです。 Executeを呼び出す前にそれを実行します。