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

如何在UnitOfWork工作单元类中实例化参数化构造的DbContext

正确实现方式

你不需要在UnitOfWork类中手动new创建SchoolContext实例,也不需要自行传入DbContextOptions参数——你已经在Program.cs中完成了DbContext的依赖注入(DI)注册,直接通过构造函数注入DbContext实例即可,这也是.NET Core/.NET 5+ 版本下使用工作单元模式的标准做法。


为什么不需要手动传Options参数

你调用AddDbContext注册时,DI容器已经自动完成了DbContextOptions<SchoolContext>的配置:连接字符串、SQL Server提供程序、上下文生命周期等规则都已经内置在容器中,容器会自动生成符合配置的DbContext实例给你。手动创建实例反而会脱离DI生命周期管理,导致多上下文实例不一致、事务失效、资源泄漏等问题。


具体实现步骤

1. 编写UnitOfWork类,通过构造函数注入DbContext

所有仓储共用同一个注入的DbContext实例,保证工作单元的事务一致性:

public interface IUnitOfWork : IDisposable
{
    IStudentRepository Students { get; }
    IGroupRepository Groups { get; }
    ICourseRepository Courses { get; }
    int SaveChanges();
}

public class UnitOfWork : IUnitOfWork
{
    private readonly SchoolContext _dbContext;

    public UnitOfWork(SchoolContext dbContext)
    {
        _dbContext = dbContext;
        // 初始化仓储,传入同一个上下文实例
        Students = new StudentRepository(_dbContext);
        Groups = new GroupRepository(_dbContext);
        Courses = new CourseRepository(_dbContext);
    }

    public IStudentRepository Students { get; private set; }
    public IGroupRepository Groups { get; private set; }
    public ICourseRepository Courses { get; private set; }

    public int SaveChanges()
    {
        return _dbContext.SaveChanges();
    }

    public void Dispose()
    {
        _dbContext.Dispose();
    }
}

2. 将UnitOfWork注册到DI容器

在Program.cs中,放在AddDbContext代码之后注册工作单元,生命周期和DbContext默认的Scoped(请求级别)保持一致:

// 原有DbContext注册代码保留不动
builder.Services.AddDbContext<SchoolContext>(options =>
   options.UseSqlServer(builder.Configuration.GetConnectionString("SchoolContext") ?? throw new InvalidOperationException("Connection string 'SchoolContext' not found.")));

// 新增工作单元注册
builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();
// 仓储如果是单独注册的也可以加在这里,比如:
// builder.Services.AddScoped<IStudentRepository, StudentRepository>();

3. 在业务层/控制器直接注入使用

不需要自己创建UnitOfWork实例,DI会自动注入,内部的DbContext和Options都会自动配置完成:

public class StudentsController : Controller
{
    private readonly IUnitOfWork _unitOfWork;

    public StudentsController(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    // 后续业务逻辑直接调用_unitOfWork.Students操作,最后SaveChanges即可
}

(不推荐)手动创建DbContext的方式

仅做原理说明,实际项目不要这么用:如果你非要手动实例化,需要自己构建DbContextOptions对象传入构造函数,等于重复写一遍你在AddDbContext里的配置:

var optionsBuilder = new DbContextOptionsBuilder<SchoolContext>();
optionsBuilder.UseSqlServer("你的连接字符串");
// 手动创建实例
using var dbContext = new SchoolContext(optionsBuilder.Options);

这种写法需要你手动管理DbContext生命周期、手动保证所有仓储共用同一个实例,事务处理复杂度极高,完全违背了工作单元模式和DI设计的初衷。


注意事项

  • 不要给SchoolContext添加无参构造函数,你当前的参数化构造函数配合DI的写法是完全正确的
  • 所有仓储必须共用UnitOfWork中注入的同一个DbContext实例,否则无法保证单次提交的事务一致性
  • 不要在任何地方手动new SchoolContext(),所有实例都交给DI容器管理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 21:15:20