首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有潜在大集合的具有重要不变量的DDD聚合

具有潜在大集合的具有重要不变量的DDD聚合
EN

Stack Overflow用户
提问于 2020-02-11 10:50:15
回答 2查看 871关注 0票数 6

我知道集合应该是小的,它们应该保护不变量。我还知道,在Aggregates中保存大量集合会影响性能。

我有一个用法,那需要保护它的不变量,但也会导致大量的收藏。

聚合是Vendor,它可以有多个活动促进(S)。每个促进都有 StartDate和EndDate。不变量是:

PromotionType

  • at
  • 在任何时间点上都可以有最多一次促销,每一个时间点都可以有最大2次促销

代码语言:javascript
复制
public Vendor : Aggregate {
    public Guid Id;
    public List<Promotion> Promotions;
    // some other Vendor props here

    public void AddPromotion(Promotion promo) {
        // protect invariants (business rules) here:
        // rule_1: if 2 promotions are already active during any time between promo.Start and promo.End then throw ex
        // rule_2: if during any time between promo.Start and promo.End there is promo with same Type then throw ex

        // if all is ok (invariants protected) then:
        Promotions.Add(promo);
    }
}

public Promotion : ValueObject {
    public PromotionType Type; // enum CheapestItemForFree, FreeDelivery, Off10PercentOfTotalBill
    public DateTime Start;
    public DateTime End;
}

正如我们所看到的,Promotions集合将增长,而新的促销将在时间上增加,而旧的促销将过期。

解决方案1)一种可能性是使Promotion本身成为一个包含VendorId的聚合,但是在这种情况下,很难保护提到的不变量。

解决方案2)另一种可能是有一个维护任务将过期(EndDate通过)移动到某个历史表,但它是臭气熏天的解决方案。

解决方案3)另一种可能性是使Promotion本身成为一个聚合,但保护域服务中的不变量,例如:

代码语言:javascript
复制
public class PromotionsDomainService {
    public Promotion CreateNewVendorPromotion(Guid vendorId, DateTime start, DateTime end, PromotionType type) {
        // protect invariants here:
        // invariants broken -> throw ex
        // invariants valid -> return new Promotion aggregate object
    }
}

..。但是在PromotionsDomainService中保护它(并返回Aggregates),我们面临种族条件和不一致性的风险(除非我们应用悲观锁)。

在这种情况下,建议采取什么DDD方法?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-02-13 21:38:59

您的聚合应该只包含为了实现其目的而需要的数据。阅读你的问题的描述,我不认为供应商需要过期的晋升任何东西。因此,您只需要保持在集合中的积极促销。

在您的AddPromotion方法中,如果有该类型的活动升级,您将返回一个错误。如果没有该类型的任何升级,您将添加它,如果该类型的升级过期,您将替换它。除非您有大量的促销类型(情况似乎并非如此),否则每种类型的促销最多只能有一次。看来这将使收藏保持在一个非常合理的规模。如果不是这样的话,请告诉我。

您很可能需要将过期的促销活动作为历史数据。但这些都应该是为这个目的而设计的读物模型,而不是总体上的。为此,聚合可以发布一个事件--它接受的每个类型--一个新的升级,侦听器将对该事件做出反应,并在历史升级表中插入一个记录。

更新:

在再次阅读了这个问题之后,我意识到你甚至不需要保留每种类型的一次晋升。您将有最多2的促销在集合中,所以集合的大小将是最大的2,除非我误解它。

票数 3
EN

Stack Overflow用户

发布于 2020-02-13 03:57:01

这是一个有趣的案例,因为我一直在为为什么聚合根需要一个实体而苦苦挣扎。我倾向于通过id引用其他聚合的聚合中的值对象,但我认为这里可能有一个实体。

解决方案可能是只具有在Vendor中注册促销的能力,从而强制执行不变量。VendorRepository只加载活动促销并将它们添加到Vendor中。这样,它们可以在任何时候过期,但是存储库只会加载相关的升级。

对于开放式促销(你可能并不需要),你甚至可以在Vendor之外终止它们,你的不变量仍然应该满足。

即使您将Promotion作为一个值对象(这是可行的),您仍然可以遵循这种方法。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60167189

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档