SqlDataReader 的转换问题
假设我有这个 sql 语句,并且我已经执行了一个 sql 命令来获取数据读取器:
"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 类型。 IE如果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);
有人有相对轻松的方法吗这样做?
Suppose i have this sql statement and I have executed a sql command to get a datareader:
"select 1 union select 2"
//.....
var rdr = cmd.ExecuteReader();
and now i want to read the value in the first column of the first row:
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
So it appears the type you cast to in C# needs to match exactly the SQL type. I.E. If the sql type is bigint, you can only cast to long. If the sql type is int, you can only cast to int. No mix and match...
I just want to get something that works regardless of the type of integer c# asks for and sql returns, as long as you could theoretically cast one to the other. So if SQL Server gives me a floating point type, and I'm asking for an int, I want the truncated int you get from doing that cast.
My goal is to make this work with generics, so I can have this function work when the generic parameter doesn't exactly match the datatype in sql server:
List<T> GetFirstColumn<T>(string sql) where T : struct
{
//get connection, execute reader
// loop:
// lst.Add( (T) rdr.GetValue(0));
}
I'd like this to work for both statments:
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);
Does anyone have a relatively painless way of doing this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
就像 Fredrik 所说,SqlDataReader 的值被装箱。您可以使用
Convert.ToInt32
将装箱值转换为int
,例如:即使 SQL Server 返回 bigint 或小数,这也会尝试转换。
Like Fredrik says, the value from SqlDataReader is boxed. You can convert a boxed value to an
int
withConvert.ToInt32
, like:This will try to convert even if SQL Server returns a bigint or a decimal.
System.Convert 将负责转换。
注意:如果
T == Nullable
,您需要使用反射做一些额外的工作来获取底层类型,并以typeof(S)
作为类型调用 ChangeType范围。显然,MS 没有使用 .NET 2.0 更新 ChangeType 函数并引入可空值。如果它是可空的,并且 dbVal 是 DBNull,则可以直接返回 null。System.Convert will take care of the conversion.
Caveat: if
T == Nullable<S>
, you need to do some extra work with reflection to get the underlying type and call ChangeType withtypeof(S)
as the type parameter. Apparently, MS didn't update the ChangeType function with .NET 2.0 and the introduction of nullables. And if it's a nullable, anddbVal is DBNull
, you can just return null.我认为您的问题是
GetValue
返回一个object
。这意味着,如果是int
,您将得到一个装在object
中的int
。那么你不能直接将其转换为long
,而必须首先将其解压为int
:我想说,使用泛型这将非常棘手。好吧,您可以创建具有两个类型参数的泛型方法;一个指定字段的类型,另一个指定您想要的类型。但我真的不认为有必要;
SqlDataReader
已经具有针对各种数据类型的方法,例如GetInt32
、GetInt64
等,因此通用方法不会真正提供任何添加的方法在这种情况下的价值。I think your problem is that
GetValue
returns anobject
. This means that in the case of anint
, you will get anint
boxed in anobject
. Then you cannot directly cast it to along
but must first unpack it as anint
:This will be quite tricky using generics, I would say. Well, you could make generic methods with two type arguments; one specifying what type the field is, and one specifying the type you want. But I don't really see the need;
SqlDataReader
already has methods for the various data types, such asGetInt32
,GetInt64
and so on, so the generic method would not really give any added value in that case.