如何建模 1-1 和循环依赖 DDD

问题描述 投票:0回答:1

我目前正在学习 DDD 并阅读蓝皮书。我已经进入真正尝试从域模型创建实现的第一阶段,并且正在努力思考如何表示循环依赖关系WITHOUT让事务跨越聚合。 假设我正在为一家汽车修理厂开发建模软件。这家汽车修理厂跟踪汽车(实体)和发动机(实体)进行维修。这些实体看起来像这样:

Public class car {

  public id: number
  public engineId: number
  public paintColor: number

}

Public class engine {
 
  public id: number
  public carId: number
  public cylendarCount: number

}

现在我觉得发动机和汽车都应该是聚合根,因为它们都是逻辑概念,可以脱离彼此而存在。例如,如果一位顾客进来需要修理他们的汽车,但将整个发动机换成我们店里的发动机,我就必须这样做

const car = carRepository.getCarById(123)
engineRepository.getEngineById(car.engineId)
engine.setCarId(null)
const newEngine = engineRepository.getByIdd(321)
car.setEngineId(newEngine.id)
newEngine.setCarId(car.id)
carRepository.save(car)
engineRepository.save(engine)
engineRepository.save(newEngine)

现在这可以工作了,但是显然有超级不必要的开销。对我现在学习 DDD 来说更重要的是,存在跨聚合的事务,我认为这是一种反模式。

  1. 我如何避免此处交易跨越两个聚合的笨拙和必要性。

  2. 聚合之间的关系通常如何表达? Id 是否保存在两个实体中?或者通常只有 1 个?

model aggregate domain-driven-design entity
1个回答
0
投票

假设我正在为一家汽车修理厂制作建模软件。

如果您谈论的是汽车、发动机以及现实世界中正在完成的工作,那么请务必注意,您的领域模型正在接收和操作的信息是“旧的”。 在帕特从斯巴鲁上拆下发动机和帕特进行数据输入以与您的数字系统共享发动机从汽车上拆下的信息之间,有至少一纳秒的时间。 您的领域模型中并没有真正的“汽车”和“发动机”,而是有“有关汽车的文档”和“有关发动机的文档”,并且您正在尝试找出如何复制某些内容提供的信息模型的“外部”进入这些文档。

数据输入本质上是向您的系统传递一条“消息”,一个或多个数字幽灵读取该消息并更新不同的文档。 因此,我们可能有一个数字幽灵将信息复制到“帕特的工作日志”中,另一个幽灵将信息复制到“斯巴鲁的维护日志”中,另一个幽灵将信息复制到“发动机的维护日志”中。

在同一交易中包含多个“聚合”并不是一种反模式,而是一种权衡——换句话说,您需要考虑对业务重要的属性,以及需要施加的约束以确保这些属性成立,以及这些约束对系统其他部分的影响。

如果“否则董事会成员会进监狱”很重要,那么对斯巴鲁日志和引擎日志的编辑总是两者兼而有之,那么将这些编辑放入同一事务中是一个很好的解决方案 -

但是

这也意味着这两个日志都必须存储在同一个地方,因此您需要一个存储设备来为您提供两者或两者都不保证(限制您对技术的选择)您需要找到一个“分布式事务”解决方案,它将引入另一组约束,等等...... 在支持汽车车身修理厂的信息系统中,所有工作日志仅精确同步可能并不那么重要;这反过来意味着您有更多的自由度来找到“最佳”解决方案(其中最佳解决方案可能是“无论如何都在单个事务中完成所有操作,因为它更容易推理)。

课程用马。


聚合之间的关系通常如何表达? Id 是否保存在两个实体中?或者通常只有 1 个?

有时两者都不是! 在某些领域,为关系提供自己的文档是有意义的。

可能有用的阅读(不是关于 DDD,不是直接的,而是关于建模):
https://ericlippert.com/2015/05/11/wizards-and-warriors-part- Five/

© www.soinside.com 2019 - 2024. All rights reserved.