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

如何实现Conditional Cascade Dependency Injection?UoW与Repo共享DB连接求助

解决方案

核心思路是利用依赖注入的Scoped生命周期保证同一请求(作用域)内共享同一个IDbConnection,同时让Uow负责连接初始化与事务管理,Repo直接复用已就绪的连接,无需嵌套结构。

步骤1:调整依赖注入注册

修正Program.cs中的服务注册逻辑,确保生命周期与依赖关系正确:

  • DBContext注册为单例(仅持有连接字符串,无状态,适合全局复用)
  • IDbConnection注册为Scoped,由DBContext动态创建(每个作用域对应一个独立连接)
  • Uow和Repo注册为Scoped,自动注入同一作用域的IDbConnection
// Program.cs
var builder = WebApplication.CreateBuilder(args);

// 1. 注册单例DBContext
builder.Services.AddSingleton<DBContext>(sp => 
    new DBContext(@"Data Source=..."));

// 2. 注册Scoped的IDbConnection,每个请求创建一次
builder.Services.AddScoped<IDbConnection>(sp => 
{
    var dbContext = sp.GetRequiredService<DBContext>();
    return dbContext.GetConnection(Models.ConnectionType.SqlLite);
});

// 3. 注册Uow和Repo,自动注入同一作用域的连接
builder.Services.AddScoped<IUow, Uow>();
builder.Services.AddScoped<IRepoAaa, RepoAaa>();

var app = builder.Build();
// ... 后续中间件配置

步骤2:保持原有Uow和Repo实现不变

你的Uow构造函数已经负责打开连接并启动事务,Repo直接复用注入的连接,无需修改核心逻辑:

// Uow实现
public class Uow : IUow, IDisposable
{
    private readonly IDbConnection _dbConnection;
    private readonly IDbTransaction _dbTransaction;
    private bool _disposedValue;

    public Uow(IDbConnection dbConnection)
    {
        _dbConnection = dbConnection;
        _dbConnection.Open();
        _dbTransaction = _dbConnection.BeginTransaction();
    }

    // 补充事务操作方法
    public void Commit() => _dbTransaction.Commit();
    public void Rollback() => _dbTransaction.Rollback();

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposedValue)
        {
            if (disposing)
            {
                _dbTransaction?.Dispose();
                _dbConnection?.Dispose();
            }
            _disposedValue = true;
        }
    }

    public void Dispose()
    {
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }
}

// RepoAaa实现
public class RepoAaa : IRepoAaa, IDisposable
{
    private readonly IDbConnection _dbConnection;
    private bool _disposedValue;

    public RepoAaa(IDbConnection dbConnection)
    {
        _dbConnection = dbConnection;
    }

    // 示例SQL执行方法(后续可直接替换为Dapper)
    public IEnumerable<SomeModel> GetAll()
    {
        using var cmd = _dbConnection.CreateCommand();
        cmd.CommandText = "SELECT * FROM SomeTable";
        using var reader = cmd.ExecuteReader();
        // ... 数据映射逻辑
        return new List<SomeModel>();
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposedValue)
        {
            _disposedValue = true;
        }
    }

    public void Dispose()
    {
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }
}

方案合理性说明

  • 单例DBContext:仅持有连接字符串,无状态且线程安全,适合全局复用。
  • Scoped连接:每个HTTP请求对应一个独立连接,既避免连接池浪费,又保证同一请求内Uow和Repo共享连接。
  • 初始化顺序保障:DI容器会先创建IDbConnection,再注入到Uow,Uow构造时自动打开连接并启动事务,后续Repo直接使用已就绪的连接。
  • 无嵌套结构:Repo直接依赖IDbConnection,无需从Uow中获取,符合你的设计要求。

额外优化建议

  • 将连接配置移至appsettings.json,避免硬编码:
    // appsettings.json
    {
      "Database": {
        "ConnectionString": "Data Source=...",
        "ConnectionType": "SqlLite"
      }
    }
    
    注册时从配置读取:
    var dbConfig = builder.Configuration.GetSection("Database");
    builder.Services.AddSingleton<DBContext>(sp => 
        new DBContext(dbConfig["ConnectionString"]));
    builder.Services.AddScoped<IDbConnection>(sp => 
    {
        var dbContext = sp.GetRequiredService<DBContext>();
        var connectionType = Enum.Parse<ConnectionType>(dbConfig["ConnectionType"]);
        return dbContext.GetConnection(connectionType);
    });
    
  • 后续引入Dapper时,直接在Repo中使用_dbConnection.Query<T>(...)即可,无需修改依赖结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 10:09:55