C#实现泛型数据库读取方法GetDataMethod<T>报类型转换错误求解
问题原因
你的代码存在核心逻辑错误,才会触发两类类型转换异常:
- 当前读取到的
tempRow是object[]类型,仅存储了一行数据库记录的原始字段值,没有任何将字段值映射到T类型实例的逻辑,直接把object[]加入List<T>必然会报类型不匹配错误。 - 出现的"System.String无法转换为MyBooks.Data.Model.Book"报错,是因为尝试直接将单个数据库字段值(比如字符串类型的书名、作者字段)强转为
Book类型,本质同样是缺失字段到实体属性的映射步骤。 - 原代码没有做数据库资源释放,长时间运行会耗尽连接池资源。
修复方案
给泛型加new()约束保证可以实例化实体,通过反射做字段和实体属性的映射,同时处理空值、可空类型转换问题,修正后的可直接运行的代码如下:
using System.Data; using System.Reflection; public List<T> GetDataMethod<T>(SqlCommand cmd) where T : new() { List<T> records = new List<T>(); // using块自动释放连接、读取器资源,避免资源泄漏 using (SqlConnection conn = getcon()) { cmd.Connection = conn; conn.Open(); using (SqlDataReader reader = cmd.ExecuteReader()) { // 提前缓存实体属性映射,减少循环内重复反射的性能损耗 Dictionary<string, PropertyInfo> propertyMap = typeof(T) .GetProperties(BindingFlags.Public | BindingFlags.Instance) .ToDictionary(p => p.Name, p => p, StringComparer.OrdinalIgnoreCase); while (reader.Read()) { T entity = new T(); for (int i = 0; i < reader.FieldCount; i++) { string columnName = reader.GetName(i); object columnValue = reader[i]; // 匹配到对应属性、属性可写、字段值非空时执行赋值 if (propertyMap.TryGetValue(columnName, out PropertyInfo prop) && prop.CanWrite && columnValue != DBNull.Value) { // 处理int?、DateTime?这类可空值类型的转换 Type targetType = prop.PropertyType; if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>)) { targetType = Nullable.GetUnderlyingType(targetType); } prop.SetValue(entity, Convert.ChangeType(columnValue, targetType)); } } records.Add(entity); } } } return records; }
使用说明
- 调用方法时直接传入实体类作为泛型参数即可,比如查询Book列表就写
GetDataMethod<Book>(yourSqlCmd) - 映射逻辑默认按忽略大小写的属性名/字段名匹配,比如数据库返回字段
book_id无法自动匹配BookId属性,写SQL时需要给字段起和实体属性同名的别名,或者自行扩展自定义映射特性。 - 如果项目有复杂查询、性能要求高的场景,不建议自己手写反射映射,直接用Dapper这类轻量ORM即可,内置的泛型查询逻辑已经覆盖了所有边界场景,性能也比手写反射好很多。
内容的提问来源于stack exchange,提问作者M. Rizwan
相关产品推荐
相关产品推荐

