ページ

2007年06月19日

Nullable型

今日は .NETのお話。

ADO.NET 2.0になって、TableAdapterというクラスが出てきました。
以前のDataAdapterとConnectionクラスが組み合わされたようなクラスで、VisualStudioでSQLやストアドプロシージャを指定してやるとデータアクセス用のメソッドを作ってくれます。
慣れすぎると自分がサルに退化しそうなくらい便利なクラスです。

更にVisualStudioが生成するメソッドは省略可能なパラメータをNull指定可能になっています。
例えば以下のようなSQLを用意しておけば Param1~Param3のパラメータはNull指定可能になるので、Param3を指定しない場合には nullを指定して省略することができます。
SELECT
 foo.*
FROM
 foo
WHERE
 ((@Param1 IS NULL) OR (foo.Param1 = @Param1))
 AND ((@Param2 IS NULL) OR (foo.Param2 = @Param2))
 AND ((@Param3 IS NULL) OR (foo.Param3 = @Param3))

using (FooTableAdapter ta = new FooTableAdapter()) {
 ta.Fill(this.Foo, param1, param2, null);
}

さて、こんな便利なTableAdapterですが、今回プログラムの都合でパラメータをHashTableで受け取るようになりました。
HashTableに含まれていればパラメータを使用し、含まれてなければnullとしたい訳です。

何も考えずにコーディング
using (FooTableAdapter ta = new FooTableAdapter()) {
 ta.Fill(this.Foo, 
 ht.Contains("Param1") ? Convert.ToInt32(ht["Param1"]) : null,
 ht.Contains("Param2") ? Convert.ToInt32(ht["Param2"]) : null,
 ht.Contains("Param3") ? Convert.ToInt32(ht["Param3"]) : null
 );
}

で、エラー。
'int' と '<null>'' の間に暗黙的な変換がないため、条件式の型がわかりません。
「intとnullは違うだろ」と。
そりゃそうですね。(でも、お前もエラーメッセージの’の数間違えているけどな...)

ならば objectにキャストしてやろう。
using (FooTableAdapter ta = new FooTableAdapter()) {
 ta.Fill(this.Foo, 
 ht.Contains("Param1") ? Convert.ToInt32(ht["Param1"] as object : null,
 ht.Contains("Param2") ? Convert.ToInt32(ht["Param2"] as object : null,
 ht.Contains("Param3") ? Convert.ToInt32(ht["Param3"] as object : null
 );
}

やっぱりエラー。
'FooTableAdapter.Fill(int?, int?, int?)' に最も適しているオーバーロード メソッドには無効な引数がいくつか含まれています。
引数 '1': 'object' から 'int?' に変換できません。
 :

今度はTableAdapter側のメソッドの型と合わない。
「objectとint?は違うだろ」と。ごもっとも。

...ん? "int?"? その"?"はナニ?

using (FooTableAdapter ta = new FooTableAdapter()) {
 ta.Fill(this.Foo, 
 ht.Contains("Param1") ? Convert.ToInt32(ht["Param1"] as int? : null,
 ht.Contains("Param2") ? Convert.ToInt32(ht["Param2"] as int? : null,
 ht.Contains("Param3") ? Convert.ToInt32(ht["Param3"] as int? : null
 );
}
試してみるとあっさり成功。
最初にNullが指定できる時点で気付けよって感じですが、intじゃなくて int?、正しくは.Net 2.0で追加された Nullable<int>でした。
using (FooTableAdapter ta = new FooTableAdapter()) {
 ta.Fill(this.Foo, 
 ht.Contains("Param1") ? Convert.ToInt32(ht["Param1"] as Nullable<int> : null,
 ht.Contains("Param2") ? Convert.ToInt32(ht["Param2"] as Nullable<int> : null,
 ht.Contains("Param3") ? Convert.ToInt32(ht["Param3"] as Nullable<int> : null
 );
}

できればConvertのメソッドで直接Nullableに変換できるメソッドがあれば便利なんですけどね。

0 件のコメント:

コメントを投稿

AltStyle によって変換されたページ (->オリジナル) /