3

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

  • 一个整数“键”,在数据库中用作主键(通过引用聚合用作外键),在应用程序内部,公共 Web API无法访问。
  • 一个基于字符串的“id”,它也唯一地标识聚合根并且可以被公共 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 键的实体,并且工作单元可以使用它在数据库中不存在的事实作为插入而不是更新的原因. 上面的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
}

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

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

4

1 回答 1

2

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

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

于 2015-09-07T09:58:55.353 回答