英文:
DDD - Is it alright to change one aggregate and save another one in the same transaction?
问题
我的聚合包括:
- 拥有多个折扣的客户,在下订单时使用这些折扣会使其失效。
- 订单必须在下单客户拥有特定折扣时进行修改。
我的问题是,当下订单时(创建新的订单对象),我必须同时持久化新的订单对象并停用适当的折扣。由于这是用户请求,这两者必须在一个事务中完成。这违反了DDD中“每个事务一个聚合修改”的规则。
是否可以在一个事务中执行这两个操作,因为持久化的新对象可以被视为没有更改,还是我应该以某种方式重新建模?只是提一下,它们位于相同的边界上下文中。
英文:
My aggregates are:
- Customer who has multiple Discounts which are invalidated if used during ordering
- Order which has to be modified if customer who places it has specific discount
My problem is that when an Order is placed (new Order object gets created) I have to both persist new Order object and deactivate appropriate Discount. This has to be done in one transaction since it is user request. This violates the rule of DDD "one aggregate modification per transaction".<br> <br>
Is it ok to do this in one transaction since new object being persisted can be considered not a change or should I somehow remodel this? Just to mention, they reside in same Bounded Context.
答案1
得分: 2
这取决于
事务会限制系统可以处理的并发操作数量。是否会成为问题,需要考虑使用情况和数据库实现细节。
另一方面,事务会让事情变得简单得多。
看到另一个回答的评论:
不能使用最终一致性,因为客户可以为多个订单使用一个折扣
在一个分布式系统(使用DDD建模)中,唯一保证这一点的方法是将折扣和订单放在同一个聚合内,因为聚合定义了一致性边界,您可以原子性地检查将要存储的相同数据上的不变量。
使用事务,您以某种方式扩展了聚合的边界,使订单和折扣包含在其中,因为不会执行两个实体上的并发操作(由于事务锁定)。
接受最终一致性通常是将不一致性作为业务领域规则来管理。一个方法是定义何时使用两次折扣的规则。
这可以在处理尝试“停用”折扣的事件的过程管理器中完成,它会拒绝命令,因为“AlreadyDisabled”。
在那一点,了解在该点可能会发生拒绝因为_AlreadyDisabled_而取消订单,或以某种方式更改订单,通知某些系统或从业务角度来看,采取最佳策略。
但在这种情况下,订单创建的“过程”考虑到了可能会第二次使用折扣的事实。
显然,技术实现事件分发的方式应该尽量减小发生这种情况的可能性,但仍然是可能的(我们正在讨论处理100%的情况)。
事务使处理这些情况变得更容易,但限制了系统可达到的规模。
允许系统大规模运行的解决方案需要处理许多细节,并需要更大的实施工作。
最后一点,域事件可以被建模和使用的方式,当一个聚合被存储时,事件被发布,您有一个跨越聚合更改和事件监听器(过程管理器)执行的单个事务。
这样做的好处是,在这种方式中,您将订单和折扣解耦,而无需让管理它们的系统部分彼此了解,或者更容易添加其他处理,而且您可以独立测试过程(可以手动发布事件到过程管理器,而不需要处理订单)。
最佳解决方案是什么?这取决于您的用例的权衡。
英文:
It depends
Transactions put a limit on the number of concurrent operations your system can handle. Is that limit a problem or not, use cases and db implementation details are needed to check.
On the other hand, transactions make things much easier.
Reading the comment on another response I saw:
> eventual consistency cannot be used because then Customer would be able to use one discount for multiple orders
On a distrubuted system (modelled using DDD) the only way to guarantee this, is having the Discount and the Order under the same aggregate, because the aggregate define the consistency boundary, you can check invariants on the same data that will be stored, atomically.
Using a transaction, you are (in some way) expanding the boundary of your aggregate to have the Order and Discount in it, as no concurrent operation can be executed on the two entities (because of the transaction locks).
Opening to eventual consistency usually is done having the inconsistencies managed as businness domain rules.
One way to do it could having the rules for when a Discount is used two times.
This can be done in the process manager handling the event that when it tries to "Deactivate" the Discount it rejects the command because "AlreadyDisabled".
The ProcessManager knowing the possibility of a rejection because AlreadyDisabled at that point can cancel the Order, or change it in some way, notifying some system or whatever is the best strategy (from the business perspective). But in that case the "process" of the order creation takes into account the fact that it can happen that a discount is used for the second time.
Obviously the implementation of techincal implementation of events dispatching should minimize the possibility of that happening, but still it will be possible (we are talking about handling 100% of the cases)
Transactions make handling these cases easier, but put a limit on the reachable scale of the system.
Solutions that allows for big scale of the system, needs to manage lot of details and require bigger effort to be implemented.
As last thing, domain events could be modelled and used in a way for which when an aggregate is stored, events get published and you have a single transaction spanning the aggregate change and all the operation done by the events listeners (process managers).
The good thing of this is that in this way you are decoupling the Order and Discount, without having the part of the systems managing them having to know each other, and/or could be simpler to add other processing, plus you can test processes in isolation (you can manually publish an event to a process manager without the need of having to have to do with the Order).
What's the best solution? It's a matter of trade-off on your use case
答案2
得分: 1
在您的特定情况下,我会将"Discount"建模为订单聚合内的值对象。这样更有意义,可以解决您的规则违例问题。
如果您希望将"Discount"作为客户聚合的一部分进行建模,那么您可以从订单中派发一个事件,监听该事件,最终更新用户。
但在您的情况下,我会选择第一种解决方案。
英文:
In your specific case I would model the Discount as value object within the Order aggregate. Make much more sense and resolve your rule violation.
If you want to keep the Discount modeled as a part of the Customer aggregate then you can dispatch an event from the Order, listen to that event and eventually update the user.
But in your case I would go for the first solution.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论