假设我有这个sql语句并且我已经执行了一个sql命令来获取一个datareader:
"select 1 union select 2"
//.....
var rdr = cmd.ExecuteReader();
现在我想读取第一行第一列中的值:
var myInt = (int)rdr.GetValue(0); //great this works
var myLong = (long)rdr.GetValue(0); //throws cast exception, even though you can cast int to long
因此,您在C#中强制转换的类型似乎需要与SQL类型完全匹配。 I.E.如果sql类型是bigint,则只能转换为long。如果sql类型是int,则只能转换为int。没有混搭......
我只是想得到一些有效的东西,无论整数c#的类型是什么,并且sql返回,只要你理论上可以将一个转换为另一个。因此,如果SQL Server给我一个浮点类型,并且我要求一个int,我想要你做的那个截断的int。
我的目标是使用泛型工作,所以当泛型参数与sql server中的数据类型不完全匹配时,我可以使用此函数:
List<T> GetFirstColumn<T>(string sql) where T : struct
{
//get connection, execute reader
// loop:
// lst.Add( (T) rdr.GetValue(0));
}
我希望这适用于两种语句:
var sql1 = "Select 1"; //sql int
var sql2 = "Select cast(1 as bigint)"; //sql equivalent of a long
var lst1 = GetFirstColumn<int>(sql1);
var lst2 = GetFirstColumn<int>(sql2);
有没有人有相对无痛的方法呢?
答案 0 :(得分:4)
System.Convert将负责转换。
T GetValue<T>(SqlDataReader rdr)
{
var dbVal = rdr.GetValue(0);
var csVal = (T)System.Convert.ChangeType(dbVal, typeof(T));
}
警告:如果T == Nullable<S>
,您需要使用反射做一些额外的工作以获取基础类型,并使用typeof(S)
作为类型参数调用ChangeType。显然,MS没有使用.NET 2.0更新ChangeType函数并引入了nullables。如果它是可空的,dbVal is DBNull
,你可以返回null。
object dbValue = 5;
//this throws
Convert.ChangeType(dbValue, typeof(int?));
//this works
if(dbValue == DBNull.Value || dbValue == null)
{
if(typeof(int?).IsNullable) //or is a class, like string
{return null;}
dbValue = null;
}
var type = GetUnderlyingType<int?>(); //== typeof(int)
Convert.ChangeType(dbValue, type);
答案 1 :(得分:4)
就像Fredrik所说,来自SqlDataReader的值是盒装的。您可以使用int
将带框值转换为Convert.ToInt32
,例如:
int i = Convert.ToInt32(read[0]);
即使SQL Server返回bigint或小数,也会尝试转换。
答案 2 :(得分:3)
我认为您的问题是GetValue
会返回object
。这意味着,如果是int
,您将在int
中获得一个object
框。然后,您无法直接将其转换为long
,但必须先将其解压缩为int
:
var myLong = (long)(int)rdr.GetValue(0);
我会说,使用泛型这将非常棘手。好吧,你可以制作带有两个类型参数的泛型方法;一个指定字段的类型,另一个指定所需的类型。但我真的没有看到需要; SqlDataReader
已经有各种数据类型的方法,例如GetInt32
,GetInt64
等等,因此在这种情况下,泛型方法实际上不会给出任何附加值。