我有一个关于聚合根(AR)之间逆关系的问题。当两个聚合根之间的关系已经确定,即经过一些操作后,一个1-1或1-N的关系已经被设置或改变。当你只允许改变一个聚合根时,逆关系是如何知道它的存在的?
我的问题是,另一个聚合根使用的业务逻辑依赖于聚合根之间的逆关系。
下面的代码是一个示例,因此可能使用的名称可能有点奇怪,但重要的部分是AR之间的关系。对于本例,我使用两个聚合根:Person和Organization以及employment作为业务流程。问题是,行为只设置了关系的一面。以下是示例:
class Organization
{
// parameter is a value object representing the Person AR.
public function startEmployment(Person $person)
{
if (in_array($person, $this->employees)) {
throw new Exception("Person is already an employee");
}
$this->employees[] = $person;
}
}
在上面的示例中,我可以更改单个AR,并且业务逻辑位于正确的位置。但是当我看另一个AR时,比如Person,我发现了一些麻烦的地方。例如,当业务需求是:人在受雇期间不得改变居住地点(可以想到一个更好的例子)。
class Person
{
public function changeLivingLocation(Location $location)
{
// what information and where do i get it from?
if (...) {
throw new Exception("May not change living location");
}
$this->livingLocation = $location;
}
}
注释已经描述了问题。我从哪里得到这些信息?AR组织包含有关就业的所有知识。最简单的解决方案是查询Organization表,但随后我将在域层中引入基础结构层。这违背了干净的架构原则(或我见过的其他DDD示例)。我可以引入一个执行业务逻辑的域服务,但随后在域服务中我可以查询组织存储库/服务。尽管如此,在领域层中仍然有一些来自基础设施层的东西。
问题(s):
- 如何从逆关系中获取信息,当关系为在另一个聚合根中确定?或者当集合root需要一个聚合的结果(例如,某些实体的计数)。
- 当我在域层内时,如何从域外获取此信息?
//读取第一个答案后更新在阅读了答案并评估了存储库接口存在于域层中的想法之后,我将其移到了域服务中。至少,我现在对域名服务的看法是这样的。我可以使用以下实现:策略评估基于存储库计数的业务逻辑。
class Person
{
public function changeLivingLocation(MayChangeLocation $policy, Location $location)
{
if ($policy->evaluate ($this)) {
throw new Exception("May not change living location");
}
$this->livingLocation = $location;
}
}
class MayChangeLocation // effective the domain service
{
public function __construct(RepositoryInterface $repository) {
$this->repository = $repository;
}
public function evaluate (Person $person)
{
$organizations = $this->repository->getOrganzationsEmployesPerson($person->getId());
// here real business logic is applied
if (count($organizations) > 0) {
return false;
}
return true;
}
}
只是对评论感到好奇:)
这就是你应该做的,不是通过基础设施层,而是通过域层中的查询。最简单的解决方案是查询Organization表,但随后我将在域层中引入基础结构层。
您可以通过存储库加载Person
中的Organization
AR,或者使用服务,或者使用CQRS中的Query
。