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

仓储模式下如何让领域层管控实体删除规则——以订单无订单项方可删除为例

让领域层强制执行订单删除规则的可行方案

这个问题问得非常到位——核心就是要把业务规则的控制权完全收回到领域层,彻底避免调用方(比如ASP.NET控制器)绕过规则直接执行删除操作。结合你目前的仓储+工作单元模式,有几个非常贴合的实现方式:

方案1:将删除规则封装到Order实体中(最推荐)

和你创建/更新订单的思路保持一致:把业务行为(包括删除的规则校验)完全封装在实体内部,外部只能调用实体暴露的合法方法,无法直接操作删除动作。

首先修改Order实体,添加删除相关的方法:

public class Order
{
    public int Id { get; private set; }
    // 用只读集合防止外部直接修改订单项
    public IReadOnlyCollection<OrderItem> Items { get; private set; } = new List<OrderItem>();
    // 如果是软删除场景,可以加这个属性
    // public bool IsDeleted { get; private set; }

    // 其他业务方法(比如创建订单的构造函数、更新订单的方法)...

    /// <summary>
    /// 执行订单删除操作,内部校验规则
    /// </summary>
    /// <exception cref="InvalidOperationException">当订单包含订单项时抛出</exception>
    public void Delete()
    {
        if (Items.Any())
        {
            throw new InvalidOperationException("无法删除包含订单项的订单,请先移除所有订单项");
        }
        // 如果是软删除,在这里标记状态:
        // IsDeleted = true;
    }
}

然后修改仓储的Remove方法,让它先调用实体的Delete方法(触发规则校验),再执行持久化操作:

public class OrderRepository : IOrderRepository
{
    private readonly YourDbContext _dbContext;

    public OrderRepository(YourDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public Order GetById(int orderId)
    {
        // 必须Include订单项,否则校验会出错
        return _dbContext.Orders
            .Include(o => o.Items)
            .FirstOrDefault(o => o.Id == orderId);
    }

    public void Remove(Order order)
    {
        // 先触发实体的删除规则校验
        order.Delete();
        
        // 如果是硬删除:
        _dbContext.Orders.Remove(order);
        // 如果是软删除,不需要Remove,只需要SaveChanges即可:
        // _dbContext.Entry(order).State = EntityState.Modified;
    }
}

这样调用方的代码完全不需要修改,还是原来的流程,但规则已经被领域层强制执行了:

var order = unitOfWork.Orders.GetById(1);
unitOfWork.Orders.Remove(order);
unitOfWork.Complete();

如果订单不符合删除条件,会直接抛出异常,调用方只需要捕获异常并处理(比如返回给前端错误提示)即可,完全不用关心校验逻辑。

方案2:在仓储层直接调用实体的校验方法

如果你不想修改实体的结构,也可以在实体中添加一个规则校验方法,然后让仓储在执行删除前调用这个方法:

public class Order
{
    // ...其他属性

    /// <summary>
    /// 校验订单是否可以被删除
    /// </summary>
    /// <returns>符合条件返回true,否则false</returns>
    public bool CanBeDeleted()
    {
        return !Items.Any();
    }
}

然后仓储的Remove方法做如下修改:

public void Remove(Order order)
{
    if (!order.CanBeDeleted())
    {
        throw new InvalidOperationException("订单包含订单项,无法删除");
    }
    _dbContext.Orders.Remove(order);
}

这个方案的效果和方案1一致,只是把校验逻辑和删除动作分开了,适合不需要封装删除行为的场景。

额外注意点

  • 一定要确保查询订单时Include关联的OrderItems,否则实体的Items集合是空的,校验会失效。
  • 如果是分布式场景,建议在数据库层面也添加一个约束(比如删除订单时检查是否存在关联的OrderItem),作为最后一道防线,避免并发场景下的数据不一致。
  • 不要让调用方直接操作DbContext,必须通过仓储和工作单元,这样才能保证规则被统一执行。

内容的提问来源于stack exchange,提问作者Álvaro García

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 13:57:36