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

如何设计数据库连接类的通用数据读取方法并注入自定义逻辑?

解决方案:用委托或接口封装可变逻辑,复用数据库操作

一、优先选委托:轻量适配单逻辑注入

如果只是需要注入一段数据读取时的处理逻辑(比如填充下拉框、树形视图),委托是最直接的选择,不用额外定义接口或类,代码简洁。

实现步骤:

  1. 封装数据库连接的创建、打开、关闭通用逻辑
  2. 给GetData方法添加委托参数,接收外部自定义处理代码
  3. 在方法内部执行通用数据库操作,读取数据时调用传入的委托

代码示例(C#):

public enum DbType
{
    SQLite,
    SqlServer
    // 可扩展其他数据库类型
}

public class DbConnector
{
    private readonly string _connectionString;
    private readonly DbType _dbType;

    public DbConnector(string connectionString, DbType dbType)
    {
        _connectionString = connectionString;
        _dbType = dbType;
    }

    // 定义委托:参数为IDataReader,适配数据读取后的处理逻辑
    public delegate void DataProcessDelegate(IDataReader reader);

    public void GetData(string sql, DataProcessDelegate processData)
    {
        using var connection = CreateConnection();
        connection.Open();
        
        using var command = connection.CreateCommand();
        command.CommandText = sql;
        
        using var reader = command.ExecuteReader();
        while (reader.Read())
        {
            // 执行外部传入的自定义处理逻辑
            processData(reader);
        }
        // using块自动释放连接、命令、读取器,无需手动Close
    }

    private IDbConnection CreateConnection()
    {
        switch (_dbType)
        {
            case DbType.SQLite:
                return new SQLiteConnection(_connectionString);
            case DbType.SqlServer:
                return new SqlConnection(_connectionString);
            default:
                throw new NotSupportedException("不支持的数据库类型");
        }
    }
}

使用方式:

// 初始化数据库连接类
var dbConnector = new DbConnector("你的连接字符串", DbType.SQLite);

// 场景1:填充下拉框
dbConnector.GetData("SELECT Id, Name FROM Categories", reader =>
{
    var id = reader.GetInt32(0);
    var name = reader.GetString(1);
    comboBox1.Items.Add(new ComboItem(id, name));
});

// 场景2:填充树形视图
dbConnector.GetData("SELECT Id, ParentId, Text FROM TreeNodes", reader =>
{
    var node = new TreeNode(reader.GetString(2))
    {
        Tag = reader.GetInt32(0)
    };
    // 根据ParentId匹配父节点的逻辑省略
    treeView1.Nodes.Add(node);
});

委托方案的注意事项:

  • 避免在委托内执行耗时操作:会拉长数据库连接占用时间,可能导致连接池耗尽
  • UI操作需注意线程安全:WinForms/WPF中要通过Invoke确保UI操作在主线程执行
  • 不要手动关闭IDataReader或IDbConnection:已由using块自动处理,手动关闭会引发异常

二、接口实现:适合复杂逻辑或多步骤处理

如果自定义逻辑需要多方法配合(比如前置验证、后置清理),可以定义接口让外部实现,注入逻辑。

代码示例:

// 定义数据处理接口
public interface IDataProcessor
{
    void ProcessRow(IDataReader reader);
    // 可扩展Initialize()、Cleanup()等方法
}

// 修改DbConnector的GetData方法
public void GetData(string sql, IDataProcessor processor)
{
    using var connection = CreateConnection();
    connection.Open();
    
    using var command = connection.CreateCommand();
    command.CommandText = sql;
    
    using var reader = command.ExecuteReader();
    while (reader.Read())
    {
        processor.ProcessRow(reader);
    }
}

// 实现接口:下拉框数据处理器
public class ComboBoxDataProcessor : IDataProcessor
{
    private readonly ComboBox _comboBox;

    public ComboBoxDataProcessor(ComboBox comboBox)
    {
        _comboBox = comboBox;
    }

    public void ProcessRow(IDataReader reader)
    {
        var id = reader.GetInt32(0);
        var name = reader.GetString(1);
        _comboBox.Items.Add(new ComboItem(id, name));
    }
}

使用方式:

var processor = new ComboBoxDataProcessor(comboBox1);
dbConnector.GetData("SELECT Id, Name FROM Categories", processor);

接口方案的优势:

  • 逻辑分层清晰,适合复杂处理场景,易扩展
  • 处理器可复用,同一逻辑能在多个地方调用
  • 便于单元测试:可Mock接口测试数据库类逻辑

三、关于Object object = new Function()方式的问题

这种用匿名类/动态对象封装逻辑的方式,在强类型语言中不推荐:

  • 无编译期类型检查,调试困难,易出隐性bug
  • 代码可读性差,维护成本高
  • 无法利用IDE智能提示,开发效率低

选择建议

  • 单一数据处理逻辑场景用委托:代码简洁,开发效率高
  • 复杂或需复用的处理逻辑用接口:结构清晰,可维护性强
  • 无论哪种方案,都要用using块自动释放数据库资源,避免手动管理连接/读取器导致的资源泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 06:27:45