我知道集合应该是小的,它们应该保护不变量。我还知道,在Aggregates中保存大量集合会影响性能。
我有一个用法,那需要保护它的不变量,但也会导致大量的收藏。
聚合是Vendor,它可以有多个活动促进(S)。每个促进都有 StartDate和EndDate。不变量是:
PromotionType
。
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本身成为一个聚合,但保护域服务中的不变量,例如:
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方法?
发布于 2020-02-13 21:38:59
您的聚合应该只包含为了实现其目的而需要的数据。阅读你的问题的描述,我不认为供应商需要过期的晋升任何东西。因此,您只需要保持在集合中的积极促销。
在您的AddPromotion方法中,如果有该类型的活动升级,您将返回一个错误。如果没有该类型的任何升级,您将添加它,如果该类型的升级过期,您将替换它。除非您有大量的促销类型(情况似乎并非如此),否则每种类型的促销最多只能有一次。看来这将使收藏保持在一个非常合理的规模。如果不是这样的话,请告诉我。
您很可能需要将过期的促销活动作为历史数据。但这些都应该是为这个目的而设计的读物模型,而不是总体上的。为此,聚合可以发布一个事件--它接受的每个类型--一个新的升级,侦听器将对该事件做出反应,并在历史升级表中插入一个记录。
更新:
在再次阅读了这个问题之后,我意识到你甚至不需要保留每种类型的一次晋升。您将有最多2的促销在集合中,所以集合的大小将是最大的2,除非我误解它。
发布于 2020-02-13 03:57:01
这是一个有趣的案例,因为我一直在为为什么聚合根需要一个实体而苦苦挣扎。我倾向于通过id引用其他聚合的聚合中的值对象,但我认为这里可能有一个实体。
解决方案可能是只具有在Vendor中注册促销的能力,从而强制执行不变量。VendorRepository只加载活动促销并将它们添加到Vendor中。这样,它们可以在任何时候过期,但是存储库只会加载相关的升级。
对于开放式促销(你可能并不需要),你甚至可以在Vendor之外终止它们,你的不变量仍然应该满足。
即使您将Promotion作为一个值对象(这是可行的),您仍然可以遵循这种方法。
https://stackoverflow.com/questions/60167189
复制相似问题