我正在使用ORM并尝试使用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)
...
}
现在我需要一个存储库来加载(并保持?)这个聚合根 - 正确吗?
repo将返回一个或多个聚合,当我访问子实体时(通过间接getter / setter - 而不是dot-notation)将延迟加载我之后的信息???
我将有另一个类作为创建工单的工厂 - 这是一个详细的流程,包括大量的业务逻辑/验证规则......
但是如果工厂创建工作订单聚合,那么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/
虽然细节非常好,但我需要对自己的解释提出第二意见。 :)
此致 亚历
答案 0 :(得分:7)
Doctrine不适合DDD。它无法处理深层域对象关系。我认为没有ORM outthere实际上很好地映射对象而没有编写大量的注释或映射元数据。如果您正确构建域模型,ORM将毫无用处。
您需要考虑一个DDD的基本规则:每个聚合一个事务。使用该规则设计域模型也可以帮助您实现持久性。你甚至会意识到你不再需要关系数据库了。即使使用RDBMS也可以帮助您实现可伸缩性。
是的,99%的案例中的存储库用于持久保存域对象。存储库应该处理映射而不是ORM,它将通过使用数据反射来自动填充域对象,这是域对象不应该关心的方法。
在删除和保存聚合时,在存储库中创建自己的映射(简单属性db table columns mapping)并不难。问题是更新聚合,但问题不是映射,而是跟踪域对象的状态更改。但同样,这不是一个映射问题,而是一个工作单元。
现在我需要一个存储库来加载(并保持?)这个聚合根 - 正确吗?
正确。存储库会持久保存域状态更改,并重新构建域的状态。repo将返回一个或多个聚合,当我访问子实体时(通过间接getter / setter - 而不是dot-notation)将延迟加载我之后的信息???
是的,你可以拥有getter(如果你使用域模型填充UI,选择使用域模型的cqrs只是为了跟踪域的状态)。你永远不应该有setter,你应该只有改变状态的方法,这些方法反映了无处不在的语言(changeName,addItemToCart)。延迟加载仅用于保存一些内存。如果内存不是问题,您还可以创建域对象最新状态的快照。是的延迟加载是ORM的工作,它迫使你在域对象中拥有某种getter,这是DDD的一个很大的限制。
但是如果工厂创建工作订单聚合,那么回购只会保留AR吗?
工厂在您的域中创建新状态。存储库重新创建曾经由工厂创建的状态。
所以存储库封装了ORM或者我应该选择哪个持久层?
是的,存储库应该处理域状态的重建。 ORM只是一个技术问题,它只是一个图书馆。无论如何,ORM是公共库/共享内核层的一部分,而存储库是基础结构层的一部分。
关于您的文件结构,您应该阅读有关DIP,IOC,DDD有界上下文的更多信息。这将帮助您基于组件构建应用程序,并将组件分离到可伸缩的应用程序。