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

如何用C#编写适配所有类的MySqlConnection通用数据获取方法

通用数据库数据获取方法实现方案

问题描述

现有多个从数据库获取数据的方法,核心逻辑完全一致,仅涉及的实体类、属性、数据库表名不同,需要重复编写大量相似代码。希望实现一个适用于所有类的通用数据获取方法,当前的核心难点是如何将MySqlDataReader中的数据自动转换为对应实体类属性的类型。计划传入类类型、列名数组和表名来实现通用方法,示例的重复代码如下:

// 期望实现的通用方法
public List<Object> getData(string className, string[] columns, string tableName) {...} 

// 重复的Client数据获取方法
public List<Client> GetClients()
{
    List<Client> list = new List<Client>();
    try
    {
        conn.Open();

        string sql = "SELECT id, clientName, info, hidden from clients";
        MySqlCommand cmd = new MySqlCommand(sql, conn);
        MySqlDataReader rdr = cmd.ExecuteReader();

        while (rdr.Read())
        {
            Client p = new Client((int)rdr[0], (string)rdr[1], (string)rdr[2], Convert.ToBoolean(rdr["hidden"]));
            list.Add(p);
        }
        rdr.Close();
        return list;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
        return null;
    }
    finally
    {
        conn.Close();
    }
}

// 重复的RepPrefix数据获取方法
public List<RepPrefix> GetRepPrefixes()
{
    List<RepPrefix> list = new List<RepPrefix>();
    try
    {
        conn.Open();

        string sql = "SELECT id, prefixName, hidden from repPrefix";
        MySqlCommand cmd = new MySqlCommand(sql, conn);
        MySqlDataReader rdr = cmd.ExecuteReader();

        while (rdr.Read())
        {
            RepPrefix p = new RepPrefix((int)rdr[0], (string)rdr[1], Convert.ToBoolean(rdr["hidden"]));
            list.Add(p);
        }
        rdr.Close();
        return list;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
        return null;
    }
    finally
    {
        conn.Close();
    }
}

解决方案

可以通过泛型+反射实现通用方法,同时优化数据库连接管理、避免SQL注入风险,以下是具体实现:

1. 通用泛型方法实现

利用泛型指定返回的实体类型,通过反射获取实体类的属性,自动完成MySqlDataReader到实体对象的转换:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using MySql.Data.MySqlClient;

public class DataAccess
{
    private string connectionString = "你的数据库连接字符串";

    // 通用数据获取方法
    public List<T> GetData<T>(string[] columns, string tableName) where T : class, new()
    {
        List<T> resultList = new List<T>();
        string columnNames = string.Join(", ", columns);
        string sql = $"SELECT {columnNames} FROM {tableName}";

        using (MySqlConnection conn = new MySqlConnection(connectionString))
        {
            try
            {
                conn.Open();
                using (MySqlCommand cmd = new MySqlCommand(sql, conn))
                {
                    using (MySqlDataReader rdr = cmd.ExecuteReader())
                    {
                        // 获取实体类的所有属性
                        PropertyInfo[] properties = typeof(T).GetProperties();

                        while (rdr.Read())
                        {
                            T entity = new T();
                            for (int i = 0; i < columns.Length; i++)
                            {
                                string columnName = columns[i];
                                // 匹配对应属性(忽略大小写)
                                PropertyInfo prop = properties.FirstOrDefault(p => p.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase));
                                if (prop != null && !rdr.IsDBNull(i))
                                {
                                    // 将Reader中的值转换为属性类型并赋值
                                    object value = Convert.ChangeType(rdr[i], prop.PropertyType);
                                    prop.SetValue(entity, value);
                                }
                            }
                            resultList.Add(entity);
                        }
                    }
                }
                return resultList;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                return null;
            }
        }
    }
}

2. 使用示例

调用通用方法获取不同实体类的数据:

DataAccess db = new DataAccess();

// 获取Client列表
List<Client> clients = db.GetData<Client>(new string[] { "id", "clientName", "info", "hidden" }, "clients");

// 获取RepPrefix列表
List<RepPrefix> repPrefixes = db.GetData<RepPrefix>(new string[] { "id", "prefixName", "hidden" }, "repPrefix");

3. 关键优化点

  • 泛型约束:where T : class, new()确保实体类有无参构造函数,方便创建实例
  • using语句:自动管理数据库连接、命令、Reader的释放,避免手动关闭的遗漏
  • 反射属性匹配:通过列名与属性名的匹配(忽略大小写),自动完成类型转换与赋值
  • SQL注入防护:如果后续需要添加查询条件,建议使用参数化查询,避免直接拼接SQL字符串

4. 针对带参构造函数的替代方案

如果实体类只有带参构造函数,可修改反射逻辑匹配构造函数参数:

// 在GetData方法的while循环中替换为以下代码
ConstructorInfo constructor = typeof(T).GetConstructors()[0];
object[] constructorParams = new object[columns.Length];
for (int i = 0; i < columns.Length; i++)
{
    if (!rdr.IsDBNull(i))
    {
        constructorParams[i] = Convert.ChangeType(rdr[i], constructor.GetParameters()[i].ParameterType);
    }
}
T entity = (T)constructor.Invoke(constructorParams);
resultList.Add(entity);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 20:45:33