如何在.NET Core 7的eShopOnWeb清洁架构中添加Unit of Work模式?
在eShopOnWeb清洁架构中添加Unit of Work模式
1. 在Domain层定义UoW抽象接口
清洁架构要求核心业务逻辑(Domain层)仅依赖抽象,因此在Domain/Interfaces目录下创建IUnitOfWork接口,封装事务管理与数据提交的核心操作:
using System.Threading; using System.Threading.Tasks; namespace Microsoft.eShopWeb.Domain.Interfaces; public interface IUnitOfWork { // 同步提交变更 int SaveChanges(); // 异步提交变更 Task<int> SaveChangesAsync(CancellationToken cancellationToken = default); // 启动事务 Task BeginTransactionAsync(CancellationToken cancellationToken = default); // 提交事务 Task CommitTransactionAsync(CancellationToken cancellationToken = default); // 回滚事务 void RollbackTransaction(); }
2. 在Infrastructure层实现UoW
Infrastructure层负责具体技术实现(如EF Core),基于项目已有的AppDbContext实现IUnitOfWork,在Infrastructure/Persistence目录下创建UnitOfWork类:
using Microsoft.eShopWeb.Domain.Interfaces; using Microsoft.EntityFrameworkCore; using System.Threading; using System.Threading.Tasks; namespace Microsoft.eShopWeb.Infrastructure.Persistence; public class UnitOfWork : IUnitOfWork { private readonly AppDbContext _dbContext; public UnitOfWork(AppDbContext dbContext) { _dbContext = dbContext; } public int SaveChanges() { return _dbContext.SaveChanges(); } public async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default) { return await _dbContext.SaveChangesAsync(cancellationToken); } public async Task BeginTransactionAsync(CancellationToken cancellationToken = default) { await _dbContext.Database.BeginTransactionAsync(cancellationToken); } public async Task CommitTransactionAsync(CancellationToken cancellationToken = default) { await _dbContext.Database.CommitTransactionAsync(cancellationToken); } public void RollbackTransaction() { _dbContext.Database.RollbackTransaction(); } }
3. 注册UoW依赖
在Infrastructure层的DependencyInjection.cs中,添加UoW的依赖注入注册,与现有Repository、DbContext的注册放在一起:
public static class DependencyInjection { public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration) { // 已有的DbContext注册代码 services.AddDbContext<AppDbContext>(options => options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly(typeof(AppDbContext).Assembly.FullName))); // 已有的Repository注册代码 services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>)); // 添加UoW注册 services.AddScoped<IUnitOfWork, UnitOfWork>(); return services; } }
4. 在Application层使用UoW
在MediatR命令/查询处理器中,注入IUnitOfWork统一管理数据提交与事务,确保业务操作的一致性:
单Repository场景
using MediatR; using Microsoft.eShopWeb.Domain.Entities; using Microsoft.eShopWeb.Domain.Interfaces; using System.Threading; using System.Threading.Tasks; namespace Microsoft.eShopWeb.Application.Products.Commands.CreateProduct; public class CreateProductCommandHandler : IRequestHandler<CreateProductCommand, int> { private readonly IRepository<Product> _productRepository; private readonly IUnitOfWork _unitOfWork; public CreateProductCommandHandler(IRepository<Product> productRepository, IUnitOfWork unitOfWork) { _productRepository = productRepository; _unitOfWork = unitOfWork; } public async Task<int> Handle(CreateProductCommand request, CancellationToken cancellationToken) { var product = new Product(request.Name, request.Price); await _productRepository.AddAsync(product, cancellationToken); // 通过UoW统一提交变更 await _unitOfWork.SaveChangesAsync(cancellationToken); return product.Id; } }
多Repository事务场景
using MediatR; using Microsoft.eShopWeb.Domain.Entities; using Microsoft.eShopWeb.Domain.Interfaces; using System; using System.Threading; using System.Threading.Tasks; namespace Microsoft.eShopWeb.Application.Products.Commands.CreateProductWithCategory; public class CreateProductWithCategoryCommandHandler : IRequestHandler<CreateProductWithCategoryCommand, int> { private readonly IRepository<Product> _productRepository; private readonly IRepository<Category> _categoryRepository; private readonly IUnitOfWork _unitOfWork; public CreateProductWithCategoryCommandHandler( IRepository<Product> productRepository, IRepository<Category> categoryRepository, IUnitOfWork unitOfWork) { _productRepository = productRepository; _categoryRepository = categoryRepository; _unitOfWork = unitOfWork; } public async Task<int> Handle(CreateProductWithCategoryCommand request, CancellationToken cancellationToken) { try { // 启动事务 await _unitOfWork.BeginTransactionAsync(cancellationToken); // 创建分类 var category = new Category(request.CategoryName); await _categoryRepository.AddAsync(category, cancellationToken); // 创建关联产品 var product = new Product(request.ProductName, request.Price, category.Id); await _productRepository.AddAsync(product, cancellationToken); // 提交变更与事务 await _unitOfWork.SaveChangesAsync(cancellationToken); await _unitOfWork.CommitTransactionAsync(cancellationToken); return product.Id; } catch (Exception) { // 回滚事务 _unitOfWork.RollbackTransaction(); throw; } } }
注意事项
- 移除原有Repository中直接调用
SaveChanges的代码,统一通过UoW提交,避免重复提交或事务不一致。 - 保持Domain层纯净性,
IUnitOfWork接口不依赖任何具体技术(如EF Core),符合清洁架构的依赖倒置原则。 - UoW的生命周期与DbContext保持一致(Scoped),确保每个请求内的事务和变更管理连贯。
内容的提问来源于stack exchange,提问作者Imran Yaseen
相关产品推荐
相关产品推荐

