質問:
SQL結果をデータテーブルではなくクラスのリストとして取得するメソッドを作成しました。問題は、データベースにintフィールドがあり、null許容であるということです。
行を。でヒットすると、nullの代わりにNULL
int
戻りDataReader
ます。に変換できないため、例外をスローDbNull.Value
します。System.Convert.ChangeType(objVal, fi.FieldType)
DbNull
int
これまでのところ悪い。objVal
私が比較したとき、私は問題を解決したと思いました、DbNull.Value
そして本当なら、代わりにこれをしました:
System.Convert.ChangeType(null, fi.FieldType)
残念ながら、結果の整数型はNULLではなく0であることに気づきました。
だから私はクラスのint型をに変更しようとしましたNullable<int>
が、値がそうでない場合、に変換できないために例外がスローされるという問題DbNull.Value
がChangeType
ありint
ますnullable<int>
...
そこで、ここで、によって返されるオブジェクトのタイプを検出し、datareader
それをnull許容値に変換しようとします。
tTypeForNullable
として正しく表示されNullable<int>
ます。しかし、結果タイプを見ると、次のようになりますint
。
何故ですか ?そしてもっと重要なこと:どうすればそれを適切に行うことができますか?
typeはオブジェクトであるため、ジェネリックメソッドを使用してを作成することはできないことに注意してくださいNullable<int>
。
bool bisnull = IsNullable(objVal);
bool bisnullt = IsNullable(fi.FieldType);
if (bisnullt)
{
Type tTypeForNullable = typeof(Nullable<>).MakeGenericType(objVal.GetType());
//object result = Activator.CreateInstance(tTypeForNullable, new object[] { objVal });
//object result = Activator.CreateInstance(typeof(Nullable<int>), new object[] { objVal });
object result = Activator.CreateInstance(tTypeForNullable, objVal);
Type tres = result.GetType();
fi.SetValue(tThisValue, System.Convert.ChangeType(result, fi.FieldType));
}
参照用の完全なルーチンは次のとおりです。
public virtual System.Collections.Generic.IList<T> GetList<T>(System.Data.IDbCommand cmd)
{
System.Collections.Generic.List<T> lsReturnValue = new System.Collections.Generic.List<T>();
T tThisValue = default(T);
Type t = typeof(T);
lock (cmd)
{
using (System.Data.IDataReader idr = ExecuteReader(cmd))
{
lock (idr)
{
while (idr.Read())
{
//idr.GetOrdinal("")
tThisValue = Activator.CreateInstance<T>();
// Console.WriteLine(idr.FieldCount);
for (int i = 0; i < idr.FieldCount; ++i)
{
string strName = idr.GetName(i);
object objVal = idr.GetValue(i);
System.Reflection.FieldInfo fi = t.GetField(strName);
//Type tttttt = fi.FieldType;
if (fi != null)
{
//fi.SetValue(tThisValue, System.Convert.ChangeType(objVal, fi.FieldType));
if (objVal == System.DBNull.Value)
{
objVal = null;
fi.SetValue(tThisValue, null);
}
else
{
//System.ComponentModel.TypeConverter conv = System.ComponentModel.TypeDescriptor.GetConverter(fi.FieldType);
bool bisnull = IsNullable(objVal);
bool bisnullt = IsNullable(fi.FieldType);
if (bisnullt)
{
Type tTypeForNullable = typeof(Nullable<>).MakeGenericType(objVal.GetType());
//object result = Activator.CreateInstance(tTypeForNullable, new object[] { objVal });
//object result = Activator.CreateInstance(typeof(Nullable<int>), new object[] { objVal });
object result = Activator.CreateInstance(tTypeForNullable, objVal);
Type tres = result.GetType();
fi.SetValue(tThisValue, System.Convert.ChangeType(result, fi.FieldType));
}
fi.SetValue(tThisValue, System.Convert.ChangeType(objVal, fi.FieldType));
}
}
else
{
System.Reflection.PropertyInfo pi = t.GetProperty(strName);
if (pi != null)
{
//pi.SetValue(tThisValue, System.Convert.ChangeType(objVal, pi.PropertyType), null);
if (objVal == System.DBNull.Value)
{
objVal = null;
pi.SetValue(tThisValue, null, null);
}
else
{
pi.SetValue(tThisValue, System.Convert.ChangeType(objVal, pi.PropertyType), null);
}
}
// Else silently ignore value
} // End else of if (fi != null)
//Console.WriteLine(strName);
} // Next i
lsReturnValue.Add(tThisValue);
} // Whend
idr.Close();
} // End Lock idr
} // End Using idr
} // End lock cmd
return lsReturnValue;
} // End Function GetList
これとともに:
public System.Data.IDataReader ExecuteReader(System.Data.IDbCommand cmd)
{
System.Data.IDataReader idr = null;
lock(cmd)
{
System.Data.IDbConnection idbc = GetConnection();
cmd.Connection = idbc;
if (cmd.Connection.State != System.Data.ConnectionState.Open)
cmd.Connection.Open();
idr = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
} // End Lock cmd
return idr;
} // End Function ExecuteReader
typeはオブジェクトであるため、ジェネリックメソッドを使用してを作成することはできないことに注意してくださいNullable<int>
。