Transactions 域驱动设计-事务一致性聚合

Transactions 域驱动设计-事务一致性聚合,transactions,domain-driven-design,aggregation,domainservices,aggregateroot,Transactions,Domain Driven Design,Aggregation,Domainservices,Aggregateroot,我正在开发一个CMS类型的应用程序,并希望使用一些ddd战术模式。情况如下: 该应用程序处理项目的创作和发布 项目在工作流组中分组在一起。在该组中,一个项目可以标记为“已发布”,一个项目可以标记为“正在工作”,任何数字都可以标记为“已存档” 只有当项目处于“工作”状态时,才能对其进行编辑 发布工作项时,它将替换相应的已发布项(如果有),然后将其标记为已存档 如果不存在草稿,可通过复制已发布版本或任何存档版本来创建新的工作版本 问题是,按照聚合应该封装系统不变量的指导,工作流组是否应该是一个包含其

我正在开发一个CMS类型的应用程序,并希望使用一些ddd战术模式。情况如下:

该应用程序处理项目的创作和发布

项目在工作流组中分组在一起。在该组中,一个项目可以标记为“已发布”,一个项目可以标记为“正在工作”,任何数字都可以标记为“已存档”

只有当项目处于“工作”状态时,才能对其进行编辑

发布工作项时,它将替换相应的已发布项(如果有),然后将其标记为已存档

如果不存在草稿,可通过复制已发布版本或任何存档版本来创建新的工作版本

问题是,按照聚合应该封装系统不变量的指导,工作流组是否应该是一个包含其所有项的聚合根

我担心的是,这会造成相当大的聚合,并且会阻止全局访问项目(即,所有交互都必须通过工作流组AR)

我看到的另一种方法是将项设置为聚合根,然后使用域服务处理事务和不变量。例如:

PublishWorkingItem(int itemId) 
{
    Item workingItem = itemRepo.GetWorkingItem(itemId);
    Guid groupId = workingItem.GroupId;
    Item publishedItem = itemRepo.GetPublishedItemForGroup(groupId);
    if(publishedItem != null) 
    {
        publisheditem.Archive();
    }
    workingItem.Publish();  
}

如果你还没有读过,我强烈建议你阅读沃恩·弗农的一系列文章。
第二部分建议您应咨询您的领域专家,以确定是否可以接受系统中存在过时数据。如果答案是肯定的,你可以考虑使用小的聚合(例如在你的领域中的项目)来保持最终的一致性而不是事务性的。例如,这可能意味着在一小段时间内,可能有两个项目处于已发布状态,但最终只会发布一个项目。您可以使用域事件实现这种行为。拥有一个大型事务性聚合也是一种选择,但如果许多用户试图同时操作同一个组,则可能会导致高并发争用。

如果您还没有,我强烈建议您阅读vaughn vernon的系列文章。
第二部分建议您应咨询您的领域专家,以确定是否可以接受系统中存在过时数据。如果答案是肯定的,你可以考虑使用小的聚合(例如在你的领域中的项目)来保持最终的一致性而不是事务性的。例如,这可能意味着在一小段时间内,可能有两个项目处于已发布状态,但最终只会发布一个项目。您可以使用域事件实现这种行为。拥有大型事务性聚合也是一种选择,但如果许多用户试图同时操作同一组,则可能会导致高并发争用。

AR应该有自己的生命周期。这是你应该能够从你的领域专家那里学到的东西

AR还涉及在高度内聚的对象图周围具有锐利的边

如果发现在另一个AR中有一个AR,则需要删除包含的AR,并将其替换为仅包含的ID或值对象

在您的情况下,例如,活动项目和存档项目之间可能存在差异,因此存档项目不属于
工作流
AR的一部分。但您可能最终将
项目
设为AR,在这种情况下,您的
工作流
AR可能包含活动项目ID/VO的列表


只是一些想法:)

AR应该有自己的生命周期。这是你应该能够从你的领域专家那里学到的东西

AR还涉及在高度内聚的对象图周围具有锐利的边

如果发现在另一个AR中有一个AR,则需要删除包含的AR,并将其替换为仅包含的ID或值对象

在您的情况下,例如,活动项目和存档项目之间可能存在差异,因此存档项目不属于
工作流
AR的一部分。但您可能最终将
项目
设为AR,在这种情况下,您的
工作流
AR可能包含活动项目ID/VO的列表

只是一些想法:)