【问题标题】:Maintain 'Current Balance' in DDD Aggregate在 DDD 聚合中保持“当前余额”
【发布时间】:2021-09-30 13:21:00
【问题描述】:

使用库存系统。

使用 C# 和实体框架。

一个 StockItem 将有许多 StockMovementStockMovement可以是购买、销售、退货、浪费等。

因此,StockItem 具有 StockLevel

StockItem 维护 StockLevel 的最佳方法是什么?

一种方法是在查询 StockItem 时对所有 StockMovements 进行求和,但如果 StockMovements 的数量过多,似乎可能最好在 StockItem 上保持 StockLevel 并在每次添加 StockMovement 时对其进行调整。

但是,如果两个单独的客户端同时处理 StockMovement,则有可能同时实现 StockItem 的两个实例(即均显示余额为 100 个单位)。

客户端 1 删除了 10 个单位,客户端 2 也删除了 10 个单位,但是在更新 StockLevel 时,两个 StockItem 实例都会调整新的 StockLevel 到 90,这是错误的。应该是 80。

因此,使用乐观并发似乎是一种选择,但我不想将其推回给用户。

应用程序层捕获并发异常然后代表客户端重试是否有意义,还是我应该采用更好的模式?

【问题讨论】:

  • “应用层捕获并发异常然后代表客户端重试是否有意义,或者我应该采用什么更好的模式?”哦,是的,这绝对是有道理的——非常常见的方法。

标签: c# entity-framework-core domain-driven-design


【解决方案1】:

使用 EF Core 的Concurrency Tokens

标记StockLevel[ConcurrencyCheck],捕捉DbUpdateConcurrencyExceptionResolving concurrency conflicts所示

【讨论】:

  • 感谢您的链接。有趣的方法。我实际上更倾向于使用 ChangeTracker.Clear 刷新工作单元并从应用层重新运行命令。在我的情况下,聚合很小,逻辑很简单。当我不想推回客户端时,可以将 Command 对象标记为“AutoRetryableOnDbConcurrencyException”,并且 CommandHandler 可以检查它以决定是再次刷新工作单元并重新运行命令还是返回客户端。
  • 是的,这是有道理的。最好重新运行,代码更少;)此文档是在 EF Core 未公开 ChangeTracker.Clear 方法时创建的。
【解决方案2】:

可以使用redis锁,因为redis是单线程的,一个请求可以同时处理StockItem

【讨论】:

    猜你喜欢
    • 2011-02-07
    • 2014-08-11
    • 1970-01-01
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    • 1970-01-01
    • 2019-07-22
    • 1970-01-01
    相关资源
    最近更新 更多