0

0

EF Core如何实现工作单元模式 EF Core工作单元(Unit of Work)教程

幻夢星雲

幻夢星雲

发布时间:2025-12-19 06:39:35

|

468人浏览过

|

来源于php中文网

原创

DbContext 就是工作单元,因其内置变更追踪、原子提交、事务一致性等能力;仅当需解耦ORM、共享上下文、统一事务或便于Mock时,才需额外抽象IUnitOfWork接口。

ef core如何实现工作单元模式 ef core工作单元(unit of work)教程

EF Core 本身已经内置了工作单元(Unit of Work)模式的核心行为——DbContext 就是一个天然的工作单元。它自动跟踪实体状态、批量提交变更、保证事务一致性,无需额外封装即可直接使用。所谓“实现工作单元模式”,更多是按需进行合理抽象和组织,而非从零造轮子。

为什么 DbContext 就是工作单元?

DbContext 在生命周期内:

  • 维护一份变更追踪(Change Tracker),记录所有 Add/Update/Remove 操作
  • 调用 SaveChanges() 或 SaveChangesAsync() 时,将所有待处理的变更一次性提交到数据库(原子性)
  • 默认在单个事务中执行(除非显式禁用或嵌套事务)
  • 支持手动开启事务(BeginTransaction)、回滚(Rollback)和提交(Commit)

何时需要进一步抽象 UoW?

当你有以下需求时,可考虑封装一层 UoW 接口:

  • 需要解耦业务逻辑与 EF Core 实现(例如未来可能切换 ORM)
  • 多个仓储(Repository)需共享同一上下文,确保跨仓储操作的一致性
  • 统一管理事务边界(尤其在 CQRS 或领域服务中)
  • 集成测试时方便 Mock 工作单元行为

注意:过度抽象可能增加复杂度,小项目通常直接用 DbContext 更清晰。

一个轻量实用的 UoW 实现

定义接口:

public interface IUnitOfWork : IDisposable
{
    DbContext Context { get; }
    Task SaveChangesAsync(CancellationToken cancellationToken = default);
    void BeginTransaction();
    void Commit();
    void Rollback();
}

实现类(复用现有 DbContext):

Dzine
Dzine

一站式AI图像生成、设计、编辑平台

下载
public class UnitOfWork : IUnitOfWork
{
    private readonly DbContext _context;
    private IDbContextTransaction _transaction;

    public UnitOfWork(DbContext context) => _context = context;

    public DbContext Context => _context;

    public async Task SaveChangesAsync(CancellationToken cancellationToken = default)
        => await _context.SaveChangesAsync(cancellationToken);

    public void BeginTransaction() => 
        _transaction ??= _context.Database.BeginTransaction();

    public void Commit()
    {
        _transaction?.Commit();
        _transaction?.Dispose();
        _transaction = null;
    }

    public void Rollback()
    {
        _transaction?.Rollback();
        _transaction?.Dispose();
        _transaction = null;
    }

    public void Dispose() => _transaction?.Dispose();
}

注册为 Scoped 服务(Startup.cs 或 Program.cs):

services.AddScoped();
services.AddDbContext(options => 
    options.UseSqlServer(connectionString));

配合 Repository 使用的典型场景

确保多个 Repository 共享同一个 DbContext(即同一个 UoW):

public class OrderService
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly IOrderRepository _orderRepo;
    private readonly IProductRepository _productRepo;

    public OrderService(
        IUnitOfWork unitOfWork,
        IOrderRepository orderRepo,
        IProductRepository productRepo)
    {
        _unitOfWork = unitOfWork;
        _orderRepo = orderRepo;
        _productRepo = productRepo;
    }

    public async Task PlaceOrderAsync(Order order)
    {
        _unitOfWork.BeginTransaction();
        try
        {
            await _orderRepo.AddAsync(order);
            var product = await _productRepo.GetByIdAsync(order.ProductId);
            product.Stock -= order.Quantity;

            await _unitOfWork.SaveChangesAsync();
            _unitOfWork.Commit();
        }
        catch
        {
            _unitOfWork.Rollback();
            throw;
        }
    }
}

关键点:所有仓储构造函数应接收 DbContext 或 IUnitOfWork,而不是自行 new DbContext。

基本上就这些。EF Core 的工作单元不复杂但容易忽略其本质——它不是必须封装的“设计模式”,而是你每天都在用的 DbContext 的自然能力。

相关专题

更多
硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1023

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

66

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

429

2025.12.29

数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

348

2023.06.29

如何删除数据库
如何删除数据库

删除数据库是指在MySQL中完全移除一个数据库及其所包含的所有数据和结构,作用包括:1、释放存储空间;2、确保数据的安全性;3、提高数据库的整体性能,加速查询和操作的执行速度。尽管删除数据库具有一些好处,但在执行任何删除操作之前,务必谨慎操作,并备份重要的数据。删除数据库将永久性地删除所有相关数据和结构,无法回滚。

2074

2023.08.14

vb怎么连接数据库
vb怎么连接数据库

在VB中,连接数据库通常使用ADO(ActiveX 数据对象)或 DAO(Data Access Objects)这两个技术来实现:1、引入ADO库;2、创建ADO连接对象;3、配置连接字符串;4、打开连接;5、执行SQL语句;6、处理查询结果;7、关闭连接即可。

347

2023.08.31

MySQL恢复数据库
MySQL恢复数据库

MySQL恢复数据库的方法有使用物理备份恢复、使用逻辑备份恢复、使用二进制日志恢复和使用数据库复制进行恢复等。本专题为大家提供MySQL数据库相关的文章、下载、课程内容,供大家免费下载体验。

255

2023.09.05

vb中怎么连接access数据库
vb中怎么连接access数据库

vb中连接access数据库的步骤包括引用必要的命名空间、创建连接字符串、创建连接对象、打开连接、执行SQL语句和关闭连接。本专题为大家提供连接access数据库相关的文章、下载、课程内容,供大家免费下载体验。

323

2023.10.09

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

71

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号