C#でDBのデータを取得する際に厄介なのがDBNull。。
DBNullはNullとは別物のため、Null判定できません。
故に三項演算子などを使ってDBNull回避する必要があります。
そこでDBNullをうまく回避しつつ、同時にキャストしてくれる関数を作れないか?と考えたところ。
私の中での最適解が生まれたので書いていきます。
public static T Convert<T>(object obj)
{
if (obj != DBNull.Value && obj != null)
{
return (T) obj;
}
return default;
}
object型は何でも受け取ることができます。
なので一度Object形で受け取り、DBNullとNullでないことをチェックします。
DBNullでもNullでもなければ、指定の型にキャストします。
Nullだった場合Defaultを返します。
これでDBNullをきれいに回避することができるのではないでしょうか??
この関数の使い方は下記のようになります。(SqlDataReaderで書いていきますが、DataRowでも使えると思います。)
using (var dataReader = command.ExecuteReader())
{
if (dataReader.HasRows)
{
while (dataReader.Read())
{
var username = Convert<string>(reader["UserName"]);
var userId = Convert<string>(reader["UserId"]);
var userpass = Convert<string>(reader["UserPass"]);
var roleId = Convert<int>(reader["RoleId"]);
}
}
}
キャストしたい型を指定して、引数にreaderのItemを投げればうまくできますね!
拡張メソッドを使えば下記のようにできますが、すべての型で拡張されてしまうので、推奨はしません。
拡張メソッドで書いてみる
public static class ObjectHelper
{
public static T ReplaceDBNull<T>(this object obj)
{
if (obj != DBNull.Value && obj != null)
{
return (T) obj;
}
return default;
}
}
こんな感じで書くと以下のような形で使えます。
using (var dataReader = command.ExecuteReader())
{
if (dataReader.HasRows)
{
while (dataReader.Read())
{
var username = reader["UserName"].ReplaceDBNull<string>();
var userId = reader["UserId"].ReplaceDBNull<string>();
var userpass = reader["UserPass"].ReplaceDBNull<string>();
var roleId = reader["RoleId"].ReplaceDBNull<int>();
}
}
}
この方法は推奨はしません。
何故ならObject型はすべての型が継承している型になっています。
それすなわち全ての型にReplaceDBNullが実装されるということになります。
個人開発ならまだいいかもしれませんが、みんなで使う際は避けたほうがいいかもしれませんね。
コメント