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

ASP.NET MVC5清洁架构中如何在EF中使用事务?

清洁架构下ASP.NET MVC5事务原子操作实现方案

我已阅读Ardalis的清洁架构文档及eShopOnWeb示例,在ASP.NET MVC5项目中实现了该架构,并完成了IUnitOfWork的实现。项目分为三层:

  • ApplicationCore
  • Infrastructure
  • UI

ApplicationCore层定义

仓储接口

public interface IRepository<TEntity> where TEntity : class
{
    List<TEntity> GetAll(ISpecification<TEntity> specification = null);
    TEntity GetById(int id);
    void Add(TEntity entity);
    void AddRange(IEnumerable<TEntity> entities);
    void Update(TEntity entity);
    void Delete(TEntity entity);
}

IUnitOfWork接口

public interface IUnitOfWork
{
    void BeginTransaction();
    IRepository<TEntity> GetRepository<TEntity>() where TEntity : class;
    void Commit();
    void TransactionCommit();
    void Rollback();
}

Infrastructure层实现

EfRepository实现

public class EfRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
    private readonly OrderExchangeEntities _context;
    private readonly DbSet<TEntity> _entities;

    public EfRepository(OrderExchangeEntities context)
    {
        _context = context;
        _entities = _context.Set<TEntity>();
    }

    public List<TEntity> GetAll(ISpecification<TEntity> specification = null)
    {
        if (specification != null)
        {
            return _entities.Where(specification.Criteria).ToList();
        }

        return _entities.ToList();
    }

    public TEntity GetById(int id)
    {
        return _entities.Find(id);
    }

    public void Add(TEntity entity)
    {
        _entities.Add(entity);
    }

    public void Update(TEntity entity)
    {
        _entities.Attach(entity);
        _context.Entry(entity).State = EntityState.Modified;
    }

    public void Delete(TEntity entity)
    {
        _entities.Remove(entity);
    }

    public void AddRange(IEnumerable<TEntity> entities)
    {
        _context.Set<TEntity>().AddRange(entities);
    }
}

EFUnitOfWork实现

public class EFUnitOfWork : IUnitOfWork
{
    private readonly OrderExchangeEntities _dbContext;
    private IDbTransaction _transaction;

    public EFUnitOfWork(OrderExchangeEntities dbContext)
    {
        _dbContext = dbContext;
    }

    public void BeginTransaction()
    {
        _transaction = _dbContext.Database.Connection.BeginTransaction();
    }

    public void Commit()
    {
        _dbContext.SaveChanges();
    }

    public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
    {
        return new EfRepository<TEntity>(_dbContext);
    }

    public void Rollback()
    {
        _transaction?.Rollback();
    }

    public void TransactionCommit()
    {
        try
        {
            _transaction?.Commit();
        }
        catch
        {
            _transaction?.Rollback();
            throw;
        }
    }
}

现有代码问题分析

当前OrderPaymentMessageService的事务实现存在三个核心问题:

  1. 错误调用了不存在的_unitOfWork.SaveChanges()方法,导致部分操作提前持久化,无法回滚
  2. 事务提交流程混乱,未结合Commit()(上下文变更写入)与TransactionCommit()(数据库事务提交)
  3. 未确保_userDocumentsService和_orderServices共享同一UnitOfWork上下文,若它们使用独立DbContext,事务无法覆盖其操作

正确原子操作实现

修改后的OrderPaymentMessageService

public class OrderPaymentMessageService : IOrderPaymentMessageService
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly IAppLogger _applogger;
    private readonly IOrderService _orderServices;
    private readonly IUserDocumentsService _userDocumentsService;
    private IRepository<OrderPaymentMessage> _orderPaymentMessageRepository;

    // 移除直接注入的仓储,统一通过UnitOfWork获取,保证上下文一致性
    public OrderPaymentMessageService(IUnitOfWork unitOfWork, IAppLogger applogger, 
                                      IOrderService orderServices, IUserDocumentsService userDocumentsService)
    {
        _unitOfWork = unitOfWork;
        _orderPaymentMessageRepository = _unitOfWork.GetRepository<OrderPaymentMessage>();
        _applogger = applogger;
        _orderServices = orderServices;
        _userDocumentsService = userDocumentsService;
    }

    public bool Create(OrderPaymentMessage orderPaymentMessage)
    {
        _unitOfWork.BeginTransaction();

        try
        {
            Guard.Against.Null(orderPaymentMessage, nameof(orderPaymentMessage));
            
            // 1. 执行支付消息添加操作
            _orderPaymentMessageRepository.Add(orderPaymentMessage);
            
            // 2. 执行文档删除操作,失败则回滚
            var documentsList = _userDocumentsService.GetAllDocumentsByOrderID(orderPaymentMessage.OrderID.GetValueOrDefault())
                                                     .Select(x => x.Id).ToList();
            bool isDeleteSuccess = _userDocumentsService.DeleteRange(documentsList);
            if (!isDeleteSuccess)
            {
                _unitOfWork.Rollback();
                return false;
            }
            
            // 3. 执行订单更新操作,失败则回滚
            bool isOrderUpdated = _orderServices.MarkAdminSendPaymentMessage(1, 1, DateTime.Now);
            if (!isOrderUpdated)
            {
                _unitOfWork.Rollback();
                return false;
            }
            
            // 4. 先将所有变更写入数据库(事务未提交)
            _unitOfWork.Commit();
            // 5. 提交事务,完成原子操作
            _unitOfWork.TransactionCommit();
            
            return true;
        }
        catch (Exception ex)
        {
            _unitOfWork.Rollback();
            _applogger.LogError(ex);
            return false;
        }
    }

    public List<OrderPaymentMessageModel> GetMessageByOrderID(int orderID)
    {
        try
        {
            Guard.Against.Zero(orderID, nameof(orderID));
            var query = new GetOrderPaymentMessageByOrderID(orderID);
            return _orderPaymentMessageRepository.GetAll(query).Select(x => new OrderPaymentMessageModel
            {
                OrderID = x.OrderID,
                ID = x.ID,
                Message = x.Message,
                CreatedDate = x.CreatedDate
            }).ToList();
        }
        catch (Exception ex)
        {
            _applogger.LogError(ex);
            return null;
        }
    }
}

关键注意事项

  1. 上下文一致性:IOrderService和IUserDocumentsService内部必须通过同一IUnitOfWork实例获取仓储,否则它们的操作不在当前事务范围内。需修改这些服务的构造函数,注入IUnitOfWork而非直接注入仓储。
  2. 事务流程规范:严格遵循「开启事务 → 执行所有业务操作 → 保存上下文变更 → 提交事务」的顺序,任何步骤失败立即回滚。
  3. 异常处理优化:TransactionCommit中捕获异常回滚后需重新抛出,确保上层感知错误。

内容的提问来源于stack exchange,提问作者Ahsan Ali Siddiqi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 17:14:56