持久性无知如何与(非根)聚合的引用一起工作?

时间:2015-09-04 04:01:49

标签: entity domain-driven-design foreign-key-relationship aggregateroot persistence-ignorance

我们有几个聚合根,有两种主要的识别方法:

  • 一个整数&#34; key&#34;,用作数据库中的主键(并通过引用聚合用作外键),并在应用程序内部,并且不< / em>可通过公共网络API访问。
  • 一个基于字符串的&#34; id&#34;,它还唯一标识聚合根, 可以通过公共Web API访问。

拥有基于整数的私有标识符和基于字符串的公共标识符有几个原因 - 例如,数据库执行得更好(8字节整数而不是可变长度字符串)并且公共标识符很难猜测。

但是,类在内部使用基于整数的标识符相互引用,如果基于整数的标识符为0,则表示该对象尚未存储到数据库中。这会产生一个问题,因为实体在 之后才能引用其他聚合根。

如何解决这个问题,或者我对持久性无知的理解存在缺陷?

关于基于字符串的标识符的编辑

基于字符串的标识符由存储库生成,连接到PostgreSQL数据库,该数据库生成标识符以确保它不会与数据库中当前的任何内容冲突。例如:

class Customer {
    public function __construct($customerKey, $customerId, $name) {
        $this->customerKey = $customerKey;
        $this->customerId = $customerId;
        $this->name = $name;
    }
}

function test(Repository $repository, UnitOfWork $unitOfWork) {
    $customer = new Customer(0, $repository->generateCustomerId(), "John Doe");
    // $customer->customerKey == 0
    $unitOfWork->saveCustomer($customer);
    // $customer->customerKey != 0
}

我假设可以使用相同的概念来创建具有非0的基于整数的键的实体,并且工作单元可以使用它在数据库中不存在的事实作为原因INSERT而不是UPDATE。上面的test()函数将变为:

function test(Repository $repository, UnitOfWork $unitOfWork) {
    $customer = new Customer($repository->generateCustomerKey(), $repository->generateCustomerId(), "John Doe");
    // $customer->customerKey != 0
    $unitOfWork->saveCustomer($customer);
    // $customer->customerKey still != 0
}

但是,鉴于上述情况,如果工作单元未按正确顺序保存数据库对象,则可能会发生错误。是解决这个问题的方法,以确保工作单元以正确的顺序保存实体吗?

我希望以上编辑能够澄清我的情况。

1 个答案:

答案 0 :(得分:2)

将聚合视为一致性边界是一种很好的方法。换句话说,两个不同的聚合具有不同的生命周期,你应该避免在同一个事务中将它们的命运捆绑在一起。从这个公理中你可以安全地说明,当从另一个聚合B的角度来看时,没有聚合A的ID将为0,因为创建A的事务尚未完成且B不可见,或者它已完成和A有一个ID。

关于双重身份,我宁愿拥有语言生成的字符串ID而不是数据库,因为我想提出一个唯一的ID会暗示一个事务,可能跨多个表。语言通常可以生成具有良好熵的唯一字符串。