6

我正在处理或尝试使用 ORM 重新建模现有应用程序并尝试尽可能地遵守 DDD。

工单是 AR,有十几个子实体。我打算像这样对这个类进行建模:

class WorkOrder {

  private $number = 0;
  private $manual = '';

  ...

  // Sub-Entities

  private $consumables; // Collection (1:m)
  private $dimensions;  // Collection (1:m)
  private $sequences;   // Collection (1:m)

  ...

}

现在我需要一个存储库来加载(并保留?)这个聚合根——对吗?

回购将返回一个或多个聚合,当我访问子实体时(通过间接 getter/setter——而不是点符号)将延迟加载我所追求的信息???

我将有另一个班级充当创建工单的工厂——这是一个详细的过程,包括大量的业务逻辑/验证规则......

但是,如果工厂创建了工单聚合,repo 是否只会保留 AR?

该工厂必须查询第三方服务(通过 REST 或其他方式),并基本上构建一个描述工作范围的已批准文档的快照。

所以存储库封装了 ORM 或者我应该选择哪个持久层?

现在我的文件结构看起来像:

WorkOrder/
  /Factory.php
  /Aggregate.php
  /Repository.php

  /Entity/Header.php
  /Entity/Shipping.php
  /Entity/Warranty.php
  /Entity/Certification.php
  ...

存储库将具有以下方法:

FindOneByTrackingNumber()
FindAllByCriteria()

save($root);

我的工厂将有如下方法:

createWorkOrderFromRpi()
createWorkOrderFromCsv()
...

我在这里阅读了几篇文章和无数帖子:

http://williamdurand.fr/2013/08/07/ddd-with-symfony2-folder-structure-and-code-first/

虽然细节非常好,但我需要对我自己的解释提出第二意见,拜托。:)

问候,亚历克斯

4

1 回答 1

14

教义不适合 DDD。它无法处理深层领域对象关系。我认为没有 ORM 可以很好地映射对象,而无需编写大量注释或映射元数据。如果您正确构建域模型,ORM 将毫无用处。

您需要考虑 DDD 的基本规则之一:每个聚合一个事务。考虑到该规则来设计您的域模型也将帮助您实现持久性。您甚至会意识到您不再需要关系数据库。即使使用 RDBMS 也会帮助您提高可伸缩性。

是的,在 99% 的情况下,存储库用于保存域对象。存储库应该处理映射而不是 ORM,ORM 将通过使用数据反射自动填充域对象,域对象不应该关心的方法。

在删除和保存聚合时,在存储库中创建自己的映射(简单的属性 db 表列映射)并不难。问题在于更新聚合,但问题不是映射,而是域对象状态变化的跟踪。但这同样不是映射问题,而是工作单元问题。

现在我需要一个存储库来加载(并保留?)这个聚合根——对吗?
正确的。存储库保持域状态更改,并重构域的状态。

回购将返回一个或多个聚合,当我访问子实体时(通过间接 getter/setter——而不是点符号)将延迟加载我所追求的信息???
是的,你可以有 getter(如果你使用域模型来填充 UI,与 cqrs 相对,你使用域模型只是为了跟踪域的状态)。你不应该有setter,你应该只有改变状态的方法,这些方法反映了无处不在的语言(changeName,addItemToCart)。延迟加载仅用于节省一些内存。如果内存不是问题,您还可以制作域对象最新状态的快照。是的,延迟加载是 ORM 的工作,它迫使您在域对象中拥有某种 getter,这对 DDD 来说是一个很大的限制。

但是,如果工厂创建了工单聚合,repo 是否只会保留 AR?
工厂在您的域中创建新状态。存储库重建了工厂曾经创建的状态。

所以存储库封装了 ORM 或者我应该选择哪个持久层?
是的,存储库应该处理域状态的重构。ORM 只是一个技术问题,它只是一个库。无论如何,ORM 是公共库/共享内核层的一部分,存储库是基础设施层的一部分。

关于您的文件结构,您应该阅读有关 DIP、IOC、DDD 有界上下文的更多信息。这将帮助您基于组件构建应用程序,并将组件解耦为可扩展的应用程序。

于 2014-06-22T08:50:23.847 回答