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

在.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 17:32:46