c# - 跨多个聚合根的域规则验证
问题描述
假设我们有以下 AR:
- 服务——负责服务配置。
- DaySchedule - 负责定义一周中每一天(周一、周二、周三...周日)的日程安排,并为日历日创建约会,例如 2020 年 8 月 15 日。
public class Service : Entity, IAggregateRoot
{
public bool Available { get; private set; }
public int TimeSlotDuration { get; private set; }
}
public class DaySchedule : Entity, IAggregateRoot
{
public DayOfWeek DayOfWeek { get; }
public List<Appointment> WorkingHours { get; private set; }
public List<Appointment> Appointments { get; private set; }
}
public class Appointment : Entity
{
public Guid ServiceId { get; }
public int AppointmentStart { get; private set; }
public int AppointmentEnd { get; private set; }
}
为了正确创建和定义约会,约会持续时间(AppointmentStart 和 AppointmentEnd 之间的时间)不得超过 Service AR 上定义的 TimeSlotDuration 值,并且服务必须可用。
现在,我面临的问题是 - 我如何正确有效地执行此操作?
我目前正在做的事情如下:
- 阅读 Service AR,获取并提取必要的值。
- 验证新约会上的属性是否有效,如果不是,则抛出异常。
我想这行得通,但有没有更好的方法?如果我没有其他需要检查的 AR 怎么办?
我想到的是最终的一致性,但我看不到如何在我的情况下应用它。也许某种 Saga 会遍历所有聚合,验证所有域规则,并且一旦它们都经过验证,然后才插入约会?
解决方案
现在,我面临的问题是 - 我如何正确有效地执行此操作?
聚合 101:如果您有两条信息必须在所有时刻都一致,那么这两条信息应该是同一聚合的一部分,因为任何可能改变一个的交易也必须考虑另一个。
当系统处于平衡状态时,两条信息必须一致,但在事物发生变化时不一定一致,它们可以分布在两个不同的集合中。
所以这是您必须解决的第一部分 - 您的约会是否需要始终与服务状态保持一致?或者就在事情停止移动的时候?
(在涉及人类的大多数情况下,商业答案是“当事情停止移动时”。)
如果您需要即时协议,那么任何时候您需要更改预约,您都需要防止服务“同时”更改,并且任何时候您对服务进行更改,您还需要考虑所有影响约会。
这反过来意味着(a)您只有一个锁,所有更改都通过,或者(b)服务和受影响的约会总是被锁定在一起。
我们组织相关信息以便将其全部锁定在一起的模式的名称是“聚合”。
当您在这种情况下,数据必须始终保持一致时,推荐的做法是重新设计您的聚合,以便单个聚合可以保持不变性。这通常会导致您以意想不到的方式分割您的域模型——请参阅 Mauro Servienti 的演讲All Our Aggregates are Wrong。
最终一致性适用于在事情发生变化时数据不需要保持一致的情况,只要事情一直在变化,直到数据保持一致。一个共同的出发点是检测一个可能的问题,将问题上报给人们进行补救。
请参阅 Rinat Abdullin 关于不断发展的流程管理器的工作,以及Pat Helland 的Memory、Guesses 和 Apologies。
推荐阅读
- neural-network - 深度学习中的基础网络和检测网络有什么区别?
- reactjs - 如何重置父组件onclick反应
- c++ - 为什么 `abs()` 的实现方式不同?
- oracle - 查询之间的条件
- python - 迭代解包函数输出 - 错误:要解包的值太多
- c - 'scanf' 后值发生变化
- python - 有没有办法使用 Twitter API 创建和销毁静音词
- cucumber - 我无法成功运行黄瓜报告
- docker - Network usage data between every two pairs of docker containers
- excel - 有条件地粘贴值,利用相邻单元格