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

C#/.NET中结合Dependency injection与Unit of Work模式的实现问题

解决方案

下面提供3种可直接落地的方案,均无需为每个仓储单独实现工厂类:

方案1:通用泛型仓储工厂

仅需实现1个泛型工厂,即可支持所有仓储的创建,兼容带UoW和无UoW两种场景。

实现代码

// 工厂接口
public interface IRepositoryFactory
{
    // 支持传入可选的UoW参数
    TRepository Create<TRepository>(IUnitOfWork? uow = null) where TRepository : IRepository;
}

// 工厂实现
public class RepositoryFactory : IRepositoryFactory
{
    private readonly IConnectionFactory _connectionFactory;

    // ConnectionFactory从DI注入
    public RepositoryFactory(IConnectionFactory connectionFactory)
    {
        _connectionFactory = connectionFactory;
    }

    public TRepository Create<TRepository>(IUnitOfWork? uow = null) where TRepository : IRepository
    {
        // 用.NET内置依赖注入工具类自动构造仓储实例,自动匹配构造参数
        return uow == null 
            ? ActivatorUtilities.CreateInstance<TRepository>(_connectionFactory)
            : ActivatorUtilities.CreateInstance<TRepository>(uow, _connectionFactory);
    }
}

注册方式

在DI容器中仅需注册一次工厂即可:

services.AddSingleton<IRepositoryFactory, RepositoryFactory>();

使用示例

// 带UoW场景
using (var uow = new UnitOfWork(_connectionFactory)) // 或者UoW也从工厂/DI获取
{
    var itemRepository = _repositoryFactory.Create<ItemRepository>(uow);
    itemRepository.Add(new Item());
    uow.Commit();
}

// 无UoW场景
var itemRepository = _repositoryFactory.Create<ItemRepository>();
var item = itemRepository.Get(itemId);

优缺点

  • 优点:实现简单,职责单一,不需要修改现有UoW和仓储的实现逻辑
  • 缺点:需要在使用仓储的类中注入IRepositoryFactory实例

方案2:UoW内置仓储提供者

将仓储创建能力内置到UoW实现中,一次获取UoW即可直接拿到所有关联的仓储,代码更简洁。

实现代码

public interface IUnitOfWork : IDisposable
{
    IDbConnection Connection { get; }
    IDbTransaction? Transaction { get; }
    void Commit();
    void Rollback();
    // 新增泛型方法获取仓储
    TRepository GetRepository<TRepository>() where TRepository : IRepository;
}

public class UnitOfWork : IUnitOfWork
{
    private readonly IConnectionFactory _connectionFactory;
    private IDbConnection? _connection;
    private IDbTransaction? _transaction;
    // 缓存已创建的仓储,避免重复实例化
    private readonly Dictionary<Type, object> _repoCache = new();

    // ConnectionFactory从DI注入
    public UnitOfWork(IConnectionFactory connectionFactory)
    {
        _connectionFactory = connectionFactory;
        _connection = _connectionFactory.CreateConnection();
        _connection.Open();
        _transaction = _connection.BeginTransaction();
    }

    public TRepository GetRepository<TRepository>() where TRepository : IRepository
    {
        var repoType = typeof(TRepository);
        if (_repoCache.TryGetValue(repoType, out var existRepo))
        {
            return (TRepository)existRepo;
        }
        // 构造仓储时自动传入当前UoW实例
        var newRepo = ActivatorUtilities.CreateInstance<TRepository>(this, _connectionFactory);
        _repoCache.Add(repoType, newRepo);
        return newRepo;
    }

    // 省略Commit、Rollback、Dispose的常规实现
}

使用示例

// UoW从DI注入获得
using (var uow = _unitOfWork)
{
    var itemRepository = uow.GetRepository<ItemRepository>();
    itemRepository.Add(new Item());
    uow.Commit();
}

优缺点

  • 优点:使用方便,代码更简洁,同一个UoW下的仓储实例自动复用,保证事务一致性
  • 缺点:UoW的职责略有扩展,不符合严格的单一职责原则,绝大多数业务场景下可忽略该问题

方案3:直接利用DI容器创建仓储(无需额外工厂类)

如果你的项目中已经将所有仓储注册到DI容器,可以直接用ActivatorUtilities手动构造,连工厂类都不需要写:

// 在需要创建仓储的类中注入IServiceProvider
private readonly IServiceProvider _serviceProvider;

// 带UoW场景
using (var uow = new UnitOfWork(_connectionFactory))
{
    // 手动传入构造参数uow,剩余依赖从DI容器自动填充
    var itemRepository = ActivatorUtilities.CreateInstance<ItemRepository>(_serviceProvider, uow);
    itemRepository.Add(new Item());
    uow.Commit();
}

// 无UoW场景
var itemRepository = ActivatorUtilities.CreateInstance<ItemRepository>(_serviceProvider);
var item = itemRepository.Get(itemId);

优缺点

  • 优点:不需要编写任何工厂类,零维护成本
  • 缺点:直接依赖IServiceProvider属于服务定位器模式,不符合显式依赖原则,对代码规范要求较高的项目慎用

关键注意点

所有方案均依赖.NET内置的ActivatorUtilities类(位于Microsoft.Extensions.DependencyInjection包,ASP.NET Core项目默认自带),会自动根据仓储的构造函数参数匹配传入的实例和DI容器中的服务,你只需要保证仓储的构造函数符合以下规则即可:

public class ItemRepository : IRepository<Item>
{
    private readonly IDbConnection _connection;
    private readonly IDbTransaction? _transaction;

    // 带UoW的构造函数
    public ItemRepository(IUnitOfWork uow, IConnectionFactory connectionFactory)
    {
        _connection = uow.Connection;
        _transaction = uow.Transaction;
    }

    // 无UoW的构造函数
    public ItemRepository(IConnectionFactory connectionFactory)
    {
        _connection = connectionFactory.CreateConnection();
    }

    // 省略仓储方法实现
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 18:09:04