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

聚合根内集合实体更新的最佳实践方案探讨

电商购物车聚合根总价同步的设计难题

领域示例

假设我们处于电商领域,存在购物车(ShoppingCart)和购物车内的商品(ShoppingCartItem)两个实体。其中购物车作为聚合根(Aggregate Root),商品仅为普通实体。购物车包含一个由旗下所有商品价格计算得出的总价(TotalPrice)。

添加商品后支持修改数量,此时购物车总价需要同步重新计算,这是设计中的难点,我不确定该如何实现最优的代码设计。

当前代码实现

ShoppingCart

public class ShoppingCart: IAggregateRoot
{
    private List<ShoppingCartItem> _items = new();

    // 其他属性和工厂方法

    public IReadOnlyCollection<ShoppingCartItem> ShoppingCartItems => _items.AsReadOnly();

    public decimal TotalPrice { get; private set; }         

    public void AddShoppingCartItem(ShoppingCartItem shoppingCartItem)
    {
        _shoppingCartItems.Add(shoppingCartItem);

        CalculateTotalPrice();
    }

    public void RemoveShoppingCartItem(ShoppingCartItem shoppingCartItem)
    {
        _shoppingCartItems.Remove(shoppingCartItem);

        CalculateTotalPrice();
    }

    private void CalculateTotalPrice()
    {
        TotalPrice = _shoppingCartItems.Sum(x => x.TotalPrice);
    }
}

ShoppingCartItem

public class ShoppingCartItem
{
    public int Id { get; private set; }

    public decimal Quantity { get; private set; }

    public decimal UnitPrice { get; private set; }

    public decimal TotalPrice { get; private set; }

    // 其他属性和工厂方法

    public void SetQuantity(decimal quantity)
    {
        Quantity = quantity;
        RecalculatePrices();
    }

    private void RecalculatePrices()
    {
        TotalPrice = Quantity * UnitPrice;
    }
}

当前代码的问题:未触发购物车总价重算

修改购物车商品时,仅该商品自身的价格会重新计算,变更通过仓储(Repository)持久化到数据库,但购物车的总价因未触发重算而不准确。

对应的命令处理器实现如下:

public class UpdateShoppingCartItemCommandHandler : IRequestHandler<UpdateShoppingCartItemCommand>
{
    private readonly IShoppingCartRepository _shoppingCartRepository;

    public UpdateShoppingCartItemCommandHandler(IShoppingCartRepository shoppingCartRepository)
    {
        _shoppingCartRepository= shoppingCartRepository;
    }

    public async Task<Unit> Handle(UpdateShoppingCartItemCommand request, CancellationToken cancellationToken)
    {
        var shoppingCart = await _shoppingCartRepository.GetById(request.ShoppingCartId);

        var shoppingCartItem = shoppingCart.ShoppingCartItems.First(x => x.Id == request.ShoppingCartItemId);

        shoppingCartItem.SetQuantity(request.Model.Quantity);

        await _shoppingCartRepository.Update(shoppingCart);

        return Unit.Value;
    }
}

可行方案1:在购物车内添加商品更新逻辑

public class ShoppingCart: IAggregateRoot
{
    // 已有的代码...

    public void UpdateShoppingCartItemQuantity(int shoppingCartItemId, decimal quantity) 
    {
        var shoppingCartItem = _shoppingCartItems.First(x => x.Id == shoppingCartItemId);
        shoppingCartItem.SetQuantity(quantity);
        CalculateTotalPrice();
    }
}

但实际场景中ShoppingCartItem会有大量属性修改方法,为每个方法都在ShoppingCart中新增对应方法显然不合理,因此不认可该方案。

可行方案2:主动触发重算

将ShoppingCart的CalculateTotalPrice方法设为公共方法:

public class ShoppingCart: IAggregateRoot
{      
    public void CalculateTotalPrice()
    {
        TotalPrice = _shoppingCartItems.Sum(x => x.TotalPrice);
    }
}

然后在命令处理器中手动触发计算:

public class UpdateShoppingCartItemCommandHandler : IRequestHandler<UpdateShoppingCartItemCommand>
{
    // 已有的代码...

    public async Task<Unit> Handle(UpdateShoppingCartItemCommand request, CancellationToken cancellationToken)
    {
        var shoppingCart = await _shoppingCartRepository.GetById(request.ShoppingCartId);

        var shoppingCartItem = shoppingCart.ShoppingCartItems.First(x => x.Id == request.ShoppingCartItemId);

        shoppingCartItem.SetQuantity(request.Model.Quantity);
        shoppingCart.CalculateTotalPrice();

        await _shoppingCartRepository.Update(shoppingCart);

        return Unit.Value;
    }
}

该方案的问题是:如果商品数量在多处被修改,开发者很容易忘记调用CalculateTotalPrice,导致总价错误。

恳请各位分享经验,给出最优解决方案,感谢!


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:57:25