最佳实践:如何在没有框架的情况下使用域模型实现多对多关系

时间:2018-11-21 09:20:19

标签: php database domain-driven-design

你好stackoverflow成员,

我正在使用纯PHP来实现域模型。我有两个实体,实体dog和实体human,是狗的主人。

这是一个多对多的关系。一个owner可以有多个dog,而一个dog由许多humans拥有(假设这只狗属于一个家庭或一对夫妇)。

我有一个doghuman的数据库表以及n:n连接表。我有两个实体,即POPO。而且我还有两个存储库,一个用于dog,一个用于human。这些存储库具有原始操作,并负责数据库查询。

哪个存储库负责管理n:n表?

示例:

实体dog具有一个属性数组,该属性数组包含所有连接的human,反之亦然。如果我创建一个像human这样的新$human = new Human('name');并让他拥有一个像dog这样已经存在的$human->addDog($dog);,谁来负责n:n连接? 我可以执行$dogRepo->Update($human->getDogs()[0]);来更新数据库中的狗,也可以执行$humanRepo->Insert($human)。 DogRepo是否也应该插入新的human(利用HumanRepo)? HumanRepo是否还应该更新dog(利用DogRepo)。还是业务逻辑对此负责? (分别从业务逻辑中调用insertHuman()updateDog())。 在所有这些方法上,我都不知道哪个存储库对n:n表负责?

听起来像是一个常见问题,但我在网络上找不到合适的解决方案。

谢谢!

2 个答案:

答案 0 :(得分:1)

在DDD中,我们根据业务规则设计汇总。每个集合保护自己的不变量。设计它们时,我们的头脑中没有表或关系表,只有不变性和一致性要求。

话虽这么说,但您遇到了困难,因为您尚未确定不变式或没有不变式。

养狗的人的行为是否有某些特殊行为?如果人类没有/没有狗,是否会拒绝某些人类命令?然后,您将{@ 1}}所拥有的狗ID(而不是狗实例!)的列表汇总。

人拥有的狗的行为与没有主人的狗的行为不同吗?然后将{@ 1}}添加到所有者ID列表。

还是它们之间的这种关系仅在用户界面中显示?然后将其添加为单独的聚合,即Human,以免用不需要的数据污染DogDogOwnershipByAHuman(id, dogId, humanId)聚合。

答案 1 :(得分:0)

两个存储库都应该只更改其对应的表,因为这是它们的主要功能(在Single responsibility principle之后)。这些存储库将由Service(具有用于管理关系的实用程序功能的包装器类)包装,其中该服务将负责正确地更改两个数据库。因此,该服务可以具有类似assignDogToHuman($humanId, $dogId)的功能,该功能将调用两个存储库并相应地更改其数据。

通过执行此操作,可以确保存储库有一个责任(更新其自己的表),并且服务具有管理dogshumans之间的关系的责任。

这还为您提供了额外的好处,即存储层现在可以更换了。即如果您决定更改数据库(例如,从Mysql更改为MongoDB),则仅需交换/更新存储库,因为assignDogToHuman调用的函数的实现应保持不变,并且对于此服务,它不底层数据库是什么。

如果您有任何疑问,希望对您有帮助