问题:
我编写了一个方法来检索作为类列表而不是数据表的 SQL 结果。问题是,我在数据库中有一个 int 字段,它可以为空。
如果我用 a 击中一行NULL
int
,则DataReader
返回DbNull.Value
而不是 null。所以System.Convert.ChangeType(objVal, fi.FieldType)
抛出一个异常,因为它不能转换DbNull
为int
.
到目前为止很糟糕。我以为我已经解决了这个问题,当我只是比较并且如果为真时,改为这样做
objVal
:DbNull.Value
System.Convert.ChangeType(null, fi.FieldType)
不幸的是,我刚刚意识到,结果整数类型是 0 而不是 NULL。
所以我只是尝试将我的类中的 int 类型更改为Nullable<int>
,但现在我遇到的问题是,当值不是时DbNull.Value
,ChangeType
会引发异常,因为它无法转换int
为nullable<int>
...
所以现在我尝试检测返回的对象的类型datareader
,并将其转换为可为空的值。
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>
.