为什么SqlDataReader返回的数据类型与原表列定义不一致?
问题原因
- SQL运算结果类型自动提升:你执行的
MAX(val - lag_value)中,两个INT类型字段做算术运算+聚合运算后,SQL Server会自动将结果类型提升为BIGINT(对应C#的System.Int64)避免运算溢出,所以SqlDataReader返回的字段类型是Int64,和原始列的INT类型无关。 - DataTable类型映射错误:你在构建
dt_main的列结构时,把SQL的bigint、smallint、tinyint全部统一映射为C#的typeof(int)(也就是Int32),这和SQL原生类型的官方对应规则不符,后续如果插入超出Int32范围的值会直接报错。 - 未处理DBNull场景:你替换为
GetInt64()也报错的核心原因是,当表中记录数≤1时,lag_value全为NULL,筛选后没有符合条件的记录,MAX返回的是DBNull,直接调用GetInt32/GetInt64都会触发类型转换异常,这两个方法不支持处理DBNull。
最优解决方案
1. 修复SqlDataReader取值逻辑
不要硬编码指定GetInt32/GetInt64,用兼容DBNull的安全取值方式:
while (sqlDataReader.Read()) { // 先判断是否为DBNull,再做类型转换 if (!sqlDataReader.IsDBNull(0)) { max_value = Convert.ToInt64(sqlDataReader[0]); } else { // 无有效记录时设置默认值,可根据业务调整 max_value = 0; } }
Convert类会自动适配不同整数类型的转换,不用关心返回的是Int32还是Int64,同时兼容DBNull处理。
2. 修正DataTable类型映射规则
按照SQL Server和.NET的官方类型映射关系修改switch逻辑:
switch (tmp_ColDataType) { case "int": T = typeof(int); // System.Int32 break; case "bigint": T = typeof(long); // System.Int64 break; case "smallint": T = typeof(short); // System.Int16 break; case "tinyint": T = typeof(byte); // System.Byte break; case "bit": T = typeof(bool); break; case "varchar": case "nvarchar": case "text": case "ntext": T = typeof(string); break; case "datetime": case "datetime2": case "smalldatetime": T = typeof(DateTime); break; default: T = typeof(string); break; }
避免后续不同整数类型插入时的类型不匹配错误。
3. 可选:强制SQL返回指定类型
如果你确定差值不会超出Int32范围,可以在SQL语句里强制转换类型,减少C#端的适配成本:
SELECT CAST(MAX(val - lag_value) AS INT) FROM (SELECT t.{Field_Name} AS val,LAG(t.{Field_Name}) OVER(ORDER BY t.{Field_Name}) as lag_value FROM {Own_Table} t) AS tmp WHERE lag_value IS NOT NULL
这样SqlDataReader返回的字段类型就是Int32,可以直接用GetInt32取值,仍需注意处理DBNull场景。
内容的提问来源于stack exchange,提问作者Dominique
相关产品推荐
相关产品推荐

