【问题标题】:Entity, Repository and composition - Dependency Injection实体、存储库和组合 - 依赖注入
【发布时间】:2012-12-23 23:54:25
【问题描述】:

我正在尝试了解 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);
        }

    }
}

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

【问题讨论】:

    标签: php dependency-injection domain-driven-design repository-pattern domain-model


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 我在 ipad 上写得太慢了...抱歉回复你了 :)
    • 更好!更多保证。
    • 谢谢(@asgerhallas)!如果只有 Event 是 AR(这就是意思),那么 EventRepository 负责持久化 - 我明白了。这里有关于存储库如何直接使用一个 EventApplication 的规则吗?我可以通过 Event 使用它,但这看起来开销很大。我可以简单地使用$eventRepository->getApplication($eventId, $appId) 方法(以及类似的更改方法),还是应该通过 Event 实体完成所有操作?
    • 任何与实体相关的行为都应该通过实体本身来调用。如果您只需要一个查询,那么您可以有一个存储库方法。也可能是您出于行为目的需要一个应用程序实例,并且通过事件加载它在性能方面是令人望而却步的。在这种情况下,您也可以考虑将应用程序设为 AR。查看有效的聚合设计链接以深入处理该主题。
    【解决方案2】:

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

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

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

    2. 1234563现在您无需说明如何持久化数据,但 ORM 可以帮助您。

    希望能有所帮助。欢迎随时提问。

    【讨论】:

      猜你喜欢
      • 2010-10-19
      • 1970-01-01
      • 2021-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-26
      • 2018-05-02
      • 1970-01-01
      相关资源
      最近更新 更多