3

我正在尝试了解 DDD,但有一些关于实体和存储库的事情我无法理解。

从这里的其他问题中,我意识到将存储库注入实体是一个坏习惯。但是当我组合对象时如何避免注入存储库?

让我们有一个简单的情况 - 事件和事件应用程序。这看起来很简单。

$event->add($application);
$eventRepository->save($event);

我相信 $application 是一个实体,所以我相信应该有一些 $applicationRepository。

这是否意味着我应该将 $applicationRepository 注入 $eventRepository 以保存 Event 实体?像

class eventRepository {

    ...

    public function save(Event $event) {
        ...

        foreach ($event->applications as $app) {
            $this->applicationRepository->save($app);
        }

        ...
    }
}

我想到的另一个解决方案是:

$eventService->addAplication($event, $application);

class $eventService {

    ...

    public function addApplication(Event $event, Application $app) {

        // simple example of validation, something like $event->isAplyable()
        if ($event->capacity > count($event->applications)) {
            $this->applicationRepository->save($app);
            $event->addApplication($app);
        }

    }
}

一种方法比另一种更好吗?还是我完全搞砸了?

4

2 回答 2

4

您应该只为每个聚合根拥有一个存储库,并且它们应该独立工作。

所以我可以看到两种场景,你选择哪种取决于业务如何做事:

  1. 如果应用程序和事件是两个不同的聚合根(可以将一个应用程序添加到多个事件中并且所有事件都应该引用同一个实体吗?),它们应该使用引用以数据方式绑定在一起,这样当您保存事件,它不会保存应用程序,而只会引用它持有的应用程序。

  2. 如果事件是聚合根并且应用程序是与它一起存在、消亡和变化的东西(并且它们共享一致性边界),那么您的事件存储库应该能够将应用程序保存为事件的一部分。现在你没有说你如何持久化数据,但是 ORM 可以帮助你。

希望能有所帮助。并随时问。

于 2013-01-09T20:02:32.213 回答
3

避免显式调用应用程序存储库的一种方法是让事件存储库持久保存与给定事件关联的应用程序实例。这本质上是您提出的第一个选项,但是根据您使用的持久性框架,代码可能看起来有些不同。例如,一些 ORM 通过可访问性支持持久性,这意味着如果您正在持久化一个事件并且框架发现可以从该事件访问的瞬态应用程序实例,它也会持久化这些实例。在这种情况下,不需要显式的应用程序存储库。

这里的想法是聚合根。如果 anEvent是聚合根并且 anApplication是组成值对象,则事件存储库必须能够持久保存整个对象图,包括关联的应用程序实例。DDD 建议每个聚合根有一个存储库,而不一定是每个实体。

可能两者Event都是Application聚合根(AR)。在这种情况下,不建议在 AR 之间使用直接对象引用,而是使用身份引用。在这种情况下,您的第二个示例将适用,但形式略有不同。事件服务应该是托管与事件相关的特定用例的应用程序服务。其中之一是添加应用程序。不同之处在于该addApplication方法应接受事件 ID 和应用程序 ID 作为参数,然后从相应的存储库加载它们。它还能够使用各自的存储库显式地持久化事件和应用程序。

查看Vaughn Vernon的 Effective Aggregate Design,了解如何确定您的领域中的 AR。

于 2013-01-09T19:41:56.140 回答