关闭。这个问题是opinion-based .它目前不接受答案。
想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题.
去年关闭。
Improve this question
我知道聚合应该很小并且它们应该保护不变量。
我也知道在聚合中保存大型集合会影响性能。
我有一个用例,需要保护它的不变量,但也会导致大量收集。
聚合是 供应商 ,并且它可以有多个事件 促销 (s)。每个促销 有 促销类型 , 开始日期 和 结束日期 .不变量是:
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
一个单独的聚合,包含 供应商 ID ,但在那种情况下很难保护提到的不变量。解决方案2)
另一种可能性是有一个维护工作,它将过期(EndDate 传递)移动到某个历史记录表,但它是 IMO 的臭解决方案。
解决方案 3)
另一种可能性是也使
Promotion
聚合本身但保护域服务中的不变量,例如: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
}
}
... 但在 中保护它促销域服务 (并返回聚合)我们冒着竞争条件和不一致的风险(除非我们应用悲观锁)。
在这种情况下,推荐的 DDD 方法是什么?
最佳答案
您的聚合应仅包含实现其目的所需的数据。阅读您的问题的描述,我认为供应商不需要任何东西的过期促销。因此,您只需要在集合中保留事件促销。
在您的 AddPromotion 方法中,如果存在该类型的事件促销,您将返回错误。如果没有该类型的任何促销,您将添加它,如果该类型的促销已过期,您将替换它。除非您有大量的促销类型(情况似乎并非如此),否则每种类型最多只能有一个促销。似乎这将使集合保持在一个非常合理的大小。如果不是这种情况,请告诉我。
您很有可能需要将过期促销作为历史数据。但是这些应该基于为此目的而设计的读取模型,而不是总体上。为此,聚合可以发布它接受新促销的每种类型的事件,并且监听器会对该事件使用react并在历史促销表中插入一条记录。
更新:
再次阅读问题后,我意识到您甚至不需要保留每种类型的促销。收藏中最多有 2 个促销事件,因此收藏的大小最多为 2,除非我误解了它。
关于domain-driven-design - 具有重要不变量的潜在大型集合的 DDD 聚合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60167189/