将smallint转换为Int32?时引发Invalid Cast Exception问题求助
解决Nullable属性与DataReader中smallint类型的转换异常问题
咱们先把问题根源理清楚:数据库里的smallint对应.NET的Int16(也就是short类型),而你的模型属性是int?(NullableDataReader取出值赋值给int?属性时,因为DataReader返回的是装箱后的Int16对象,CLR没法自动把装箱的Int16直接转换成int?,所以就抛出了InvalidCastException。
下面给你几个实用的解决方案:
方案一:通用类型转换(推荐)
用Convert.ChangeType来自动适配类型转换,不管是smallint转int?,还是其他数值/Nullable类型的转换都能兼容,通用性最强:
foreach (var property in _properties) { property.SetValue(model, null, null); var lowerPropertyName = property.Name.ToLower(); if (columnsInDataReader.Contains(lowerPropertyName)) { var valueFromReader = _dataReader[property.Name]; if (valueFromReader != DBNull.Value) { // 把DataReader的值转换成属性对应的目标类型 var convertedValue = Convert.ChangeType(valueFromReader, property.PropertyType); property.SetValue(model, convertedValue); } } }
这个方法会自动处理数值类型的向上转换(比如short转int),同时也能完美适配Nullable类型的装箱需求。
方案二:针对Nullable类型的精准处理
如果想更针对性地处理Nullable属性,可以先获取它的底层非Nullable类型再转换,逻辑更清晰:
foreach (var property in _properties) { property.SetValue(model, null, null); var lowerPropertyName = property.Name.ToLower(); if (columnsInDataReader.Contains(lowerPropertyName)) { var valueFromReader = _dataReader[property.Name]; if (valueFromReader != DBNull.Value) { // 取出Nullable类型的底层类型,非Nullable类型则直接用自身 Type targetType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType; var convertedValue = Convert.ChangeType(valueFromReader, targetType); property.SetValue(model, convertedValue); } } }
方案三:特定类型的硬编码转换(局限性强)
如果你的场景里只有smallint转int?这一种类型问题,也可以直接读取为short再转成int,但这个方案只适用于单一场景,不推荐通用使用:
foreach (var property in _properties) { property.SetValue(model, null, null); var lowerPropertyName = property.Name.ToLower(); if (columnsInDataReader.Contains(lowerPropertyName)) { var valueFromReader = _dataReader[property.Name]; if (valueFromReader != DBNull.Value) { if (property.PropertyType == typeof(int?)) { // 先读取为short,再转成int? short shortValue = _dataReader.GetInt16(_dataReader.GetOrdinal(property.Name)); property.SetValue(model, (int?)shortValue); } else { property.SetValue(model, valueFromReader); } } } }
最后提个小优化:用_dataReader.GetOrdinal(property.Name)代替直接索引列名,不仅能避免大小写匹配问题,性能也会更好一点。
内容的提问来源于stack exchange,提问作者Faheem Rasheed
相关产品推荐
相关产品推荐

