基于Dapper实现多数据库连接的方案合理性及非抽象类替代方式咨询
Dapper多数据库连接实现分析:合理性与无抽象类替代方案
一、当前抽象类实现的合理性
你当前基于抽象类BaseRepository的实现是合理的,核心优势包括:
- 代码复用:将Dapper通用操作(如
ExecuteAsync)统一封装在基类,避免每个业务Repository重复编写相同逻辑,符合DRY原则。 - 多库适配清晰:结合
[FromKeyedServices]注入指定Key的数据库连接,能在依赖注入容器中通过注册不同Key的IDbConnection实例,轻松实现多数据库的区分与切换,适配多库场景需求。 - 异常处理统一:基类中统一捕获并包装异常,上层Repository无需重复处理通用异常逻辑,降低代码冗余。
可以优化的小细节:
- 异常消息中的"retrieving the company"与
ExecuteAsync操作不匹配,建议改为通用描述(如"执行SQL操作时出错")。 - 若子类需要直接操作数据库连接,可将
_dbConnection的访问修饰符改为protected。
二、无需抽象类的替代实现方案
方案1:IDbConnection扩展方法
将通用Dapper操作封装为IDbConnection的扩展方法,业务Repository直接注入指定连接并调用扩展方法:
// 扩展方法类 public static class DapperExtensions { public static async Task<int> ExecuteWithExceptionHandleAsync(this IDbConnection dbConnection, string sql, object? param = null, IDbTransaction? transaction = null, int? commandTimeout = null, CommandType? commandType = null) { try { return await dbConnection.ExecuteAsync(sql, param, transaction, commandTimeout, commandType) .ConfigureAwait(false); } catch (Exception ex) { throw new Exception("执行SQL操作时出错", ex); } } } // 业务Repository public class PRepository { private readonly IDbConnection _dbConnection; public PRepository([FromKeyedServices(DbConnectionKeys.PCMRead)] IDbConnection dbConnection) { _dbConnection = dbConnection; } public async Task<int> UpdateProductAsync(string sql, object productParams) { return await _dbConnection.ExecuteWithExceptionHandleAsync(sql, productParams); } }
优势:无需继承关系,灵活性更高,Repository可按需选择是否使用扩展方法,避免强耦合。
方案2:组合式Dapper操作服务
创建独立的Dapper操作服务类,通过组合方式在Repository中复用通用逻辑:
// 操作服务接口与实现 public interface IDapperOperationService { Task<int> ExecuteAsync(IDbConnection dbConnection, string sql, object? param = null, IDbTransaction? transaction = null, int? commandTimeout = null, CommandType? commandType = null); } public class DapperOperationService : IDapperOperationService { public async Task<int> ExecuteAsync(IDbConnection dbConnection, string sql, object? param = null, IDbTransaction? transaction = null, int? commandTimeout = null, CommandType? commandType = null) { try { return await dbConnection.ExecuteAsync(sql, param, transaction, commandTimeout, commandType) .ConfigureAwait(false); } catch (Exception ex) { throw new Exception("执行SQL操作时出错", ex); } } } // 业务Repository public class PRepository { private readonly IDbConnection _dbConnection; private readonly IDapperOperationService _dapperService; public PRepository([FromKeyedServices(DbConnectionKeys.PCMRead)] IDbConnection dbConnection, IDapperOperationService dapperService) { _dbConnection = dbConnection; _dapperService = dapperService; } public async Task<int> DeleteProductAsync(string sql, object deleteParams) { return await _dapperService.ExecuteAsync(_dbConnection, sql, deleteParams); } }
优势:遵循"组合优先于继承"的设计原则,降低类之间的耦合度,Dapper操作服务可单独进行单元测试,Repository职责更单一。
方案3:Repository直接封装Dapper操作
若业务Repository的操作差异较大,无需统一通用逻辑,可直接在Repository中注入连接并编写Dapper操作:
public class PRepository { private readonly IDbConnection _dbConnection; public PRepository([FromKeyedServices(DbConnectionKeys.PCMRead)] IDbConnection dbConnection) { _dbConnection = dbConnection; } public async Task<int> AddProductAsync(string sql, object productParams) { try { return await _dbConnection.ExecuteAsync(sql, productParams) .ConfigureAwait(false); } catch (Exception ex) { throw new Exception("添加产品时出错", ex); } } }
优势:无额外抽象层,实现简单直接,适合每个Repository有独特业务逻辑的场景。
内容的提问来源于stack exchange,提问作者user2797910
相关产品推荐
相关产品推荐

