在.NET Core的DataLibrary中集成ADO.NET与Dapper事务遇依赖注入问题
.NET Core下Dapper+ADO.NET事务集成的调整方向
1. 修正IDbConnection的DI注册
.NET Web请求是多线程场景,绝对不能把IDbConnection注册为单例,必须用Scoped生命周期,每个请求分配独立连接:
// Program.cs builder.Services.AddScoped<IDbConnection>(sp => { var conn = new SqlConnection(builder.Configuration.GetConnectionString("DefaultConnection")); conn.Open(); // 也可在使用时按需打开,根据业务习惯调整 return conn; });
2. 用Unit of Work封装事务管理
放弃原项目中让DBLibrary自行持有事务的模式,改用Scoped的Unit of Work统一管理事务生命周期,确保每个请求的事务独立隔离:
// 定义事务管理接口 public interface IUnitOfWork : IDisposable { IDbTransaction Transaction { get; } void Commit(); void Rollback(); } // 实现类 public class UnitOfWork : IUnitOfWork { private readonly IDbConnection _conn; private IDbTransaction _transaction; public UnitOfWork(IDbConnection conn) { _conn = conn; } public IDbTransaction Transaction { get { if (_transaction == null) { _transaction = _conn.BeginTransaction(); } return _transaction; } } public void Commit() { _transaction?.Commit(); Dispose(); } public void Rollback() { _transaction?.Rollback(); Dispose(); } public void Dispose() { _transaction?.Dispose(); _transaction = null; // 不要在此关闭连接!连接是Scoped的,DI会在请求结束时自动处理 } } // 注册到DI容器 builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();
3. 重构DBLibrary的CRUD逻辑
让DBLibrary通过构造函数注入IUnitOfWork和IDbConnection,根据是否需要事务自动选择连接方式:
public class DBLibrary { private readonly IUnitOfWork _unitOfWork; private readonly IDbConnection _conn; public DBLibrary(IUnitOfWork unitOfWork, IDbConnection conn) { _unitOfWork = unitOfWork; _conn = conn; } public void Save<T>(T entity) where T : class { // 优先使用事务绑定的连接,无事务则使用独立连接 var targetConn = _unitOfWork.Transaction?.Connection ?? _conn; var transaction = _unitOfWork.Transaction; // 执行Dapper操作,传入事务参数(如果有) targetConn.Execute("INSERT INTO YourTable (...) VALUES (...)", entity, transaction); } } // 注册DBLibrary为Scoped builder.Services.AddScoped<DBLibrary>();
4. 业务层调用事务的正确方式
在业务逻辑中注入IUnitOfWork,手动控制事务的提交与回滚:
public class BatchService { private readonly DBLibrary _dbLib; private readonly IUnitOfWork _uow; public BatchService(DBLibrary dbLib, IUnitOfWork uow) { _dbLib = dbLib; _uow = uow; } public void ExecuteBatchOperation() { try { _dbLib.Save(new UserEntity { Name = "Test" }); _dbLib.Save(new OrderEntity { UserId = 1, Amount = 100 }); _uow.Commit(); } catch { _uow.Rollback(); throw; } } }
解决Program.cs报错的核心要点
- 确保所有依赖服务(IDbConnection、IUnitOfWork、DBLibrary)都正确注册,且生命周期统一为Scoped,避免循环依赖或生命周期不匹配问题。
- 绝对不要在DBLibrary中用静态字段存储IDbConnection或IDbTransaction,DI容器无法解析静态依赖,这是导致
builder.Build()报错的常见原因。
内容的提问来源于stack exchange,提问作者Elizabeth
相关产品推荐
相关产品推荐

