You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ADO.NET包装类中返回实体类列表而非DataTable?

嘿,这个需求其实很常见,咱们可以通过泛型+反射的方式来实现,不用引入复杂的ORM,完全贴合你简化ADO.NET代码的目标。我给你一步步拆解解决方案:

首先先修正一个小细节:你原来的ParametersGroup里paramValue是string类型,这会限制参数类型(比如数字、日期没法直接传),建议改成object类型,兼容性更好:

public class ParametersGroup
{
    public string paramName { get; set; }
    public object paramValue { get; set; } // 改为object类型支持多类型参数
}

核心实现:泛型查询+实体映射

我们要把ExecuteQuery改成泛型方法,让它能返回任意实体类型的列表,同时实现一个辅助方法把DataRow的数据自动映射到实体属性上。

1. 改造ExecuteQuery为泛型方法

替换原来返回DataTable的方法,改成返回List<T>,并添加where T : new()约束(确保能创建实体类实例):

internal class adoWrapper 
{ 
    public string _connectionString { get; set; } 
    private static readonly Dictionary<Type, PropertyInfo[]> _propertyCache = new Dictionary<Type, PropertyInfo[]>();

    public adoWrapper(string connectionString) 
    { 
        _connectionString = connectionString; 
    } 

    // 你的其他方法(ExecuteNonQuery、ExecuteScalar)保持不变...

    public List<T> ExecuteQuery<T>(string query, List<ParametersGroup> parameters) where T : new()
    {
        if (string.IsNullOrEmpty(query))
        {
            throw new ArgumentException("Query cannot be null or empty", nameof(query));
            // 用ArgumentException替代NullReferenceException,更符合.NET异常规范
        }

        var resultList = new List<T>();
        DataTable dt = new DataTable();

        using (SqlConnection con = new SqlConnection(_connectionString))
        using (SqlCommand cmd = new SqlCommand(query, con))
        {
            if (parameters != null && parameters.Count > 0)
            {
                foreach (var param in parameters)
                {
                    // 处理null值,避免传入null导致数据库报错
                    cmd.Parameters.AddWithValue(param.paramName, param.paramValue ?? DBNull.Value);
                }
            }

            cmd.CommandType = CommandType.Text;
            con.Open();

            using (SqlDataAdapter ad = new SqlDataAdapter(cmd))
            {
                ad.Fill(dt);
            }
        }

        // 将DataTable每行数据映射为实体
        foreach (DataRow row in dt.Rows)
        {
            var entity = MapDataRowToEntity<T>(row);
            resultList.Add(entity);
        }

        return resultList;
    }
}

2. 实现DataRow到实体的映射逻辑

用反射读取实体类的属性,根据列名(和属性名对应)自动赋值,同时处理类型转换:

private T MapDataRowToEntity<T>(DataRow row) where T : new()
{
    var entity = new T();
    var entityType = typeof(T);

    // 缓存实体属性,避免重复反射提升性能
    if (!_propertyCache.TryGetValue(entityType, out var properties))
    {
        properties = entityType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
        _propertyCache[entityType] = properties;
    }

    foreach (var prop in properties)
    {
        // 忽略大小写匹配列名,更灵活
        var columnName = row.Table.Columns.Cast<DataColumn>()
            .FirstOrDefault(c => c.Name.Equals(prop.Name, StringComparison.OrdinalIgnoreCase))?.Name;

        if (columnName != null && !row.IsNull(columnName))
        {
            var columnValue = row[columnName];
            // 处理类型转换,适配数据库类型与实体属性类型差异
            var convertedValue = Convert.ChangeType(columnValue, prop.PropertyType);
            prop.SetValue(entity, convertedValue);
        }
    }

    return entity;
}

使用示例

假设你有一个TableA实体类:

public class TableA
{
    public int Id { get; set; }
    public string UserName { get; set; }
    public DateTime CreateTime { get; set; }
}

调用时直接指定泛型类型即可:

var dbWrapper = new adoWrapper("your_connection_string");
var parameters = new List<ParametersGroup>
{
    new ParametersGroup { paramName = "@Id", paramValue = 1001 }
};

// 直接获取实体列表
List<TableA> tableAData = dbWrapper.ExecuteQuery<TableA>(
    "SELECT Id, UserName, CreateTime FROM TableA WHERE Id = @Id", 
    parameters
);

额外说明

  • 这个方案完全基于你现有的ADO.NET包装类,没有引入任何ORM依赖,符合你“简化代码但不用ORM”的需求。
  • 缓存反射属性的逻辑可以避免重复反射带来的性能损耗,对于高频调用场景很有用。
  • 如果需要更复杂的映射规则(比如列名和属性名不一致),可以给实体属性加自定义特性(比如[Column("DbColumnName")]),然后在映射逻辑里读取特性值来匹配列名。

内容的提问来源于stack exchange,提问作者Tanwer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:21:11