DDD中Repository的职责

穆阳嘉
2023-12-01

入参与出参

如果考虑到DummyRepository,那么需要将Repository的入参和出参定义为Domain
如果考虑到Repository可能是一个远程服务,那么可能需要定义为ValueObject
供GET方法使用的retrieve,毫无疑问,这个方法只需要返回ValueObject方法即可,但是Repository如何知道当前查询是为了修改的查询还是为了呈现的查询呢?
在CQRS模式下,CommandService的repository就是为了修改的查询

id

这里需要进行区分,对于domain的id也许应该由Repository来处理,因为domain不关心也无法很好的处理。但是对于domain的属性的id,也许由domain来处理是可以的,一方面从id上加强了业务关系,并且不需要全局的id生成器,但是这样做有个问题就是要依赖domain的id要生成。
如果向外发消息或者调用前都完成持久化,那么由Repository来生成也没啥问题,可能唯一的问题就是domain没有setId()这个方法
在更一般的情况下,domain的属性可以没有id,但是jpa不答应

gmt_modified

如果考虑到数据的可见性,那么gmt_modified应该由数据库来决定。

Operation

为了列表上呈现方便,最好把operation也进行持久化。但是这样做的话业务规则的变更就会刷很多数据。另一种方法就是把这种冗余字段单独成列方便刷。
抛出去的Message里应该不包括operation

查询

如果仅仅是把Repository理解为一个存储功能,没有查找功能的话可能会给Repository分配一个Stream<SomeObject> retrieveAll的功能.然后对返回的Stream传入Filter来进行过滤.在这种使用方法下,基于RMDB的Repository难以将代码转化为SQL,另外其比较也有两种,一种是SomeObject的某个属性和入参相比较(这时入参可以理解为常量),另一种情况是SomeObject的两个属性进行比较.如果把后者的比较逻辑放入Stream中,是难以转化为SQL的,这个时候恐怕需要进行转化,也就是提供有个冗余字段(也就是通过对SomeObject的两个属性进行比较得到的boolean)来将第二种情况转为第一种情况.这样就带来了两个问题,一个是引入了新的业务含义的字段(有时这样是合理的),另外也与业务的原始语意不符.
如果站在CQRS的模式看待这个问题,那么查询操作就只存在于QueryService中,毕竟在CommandService中往往通过ID来获取一个数据.那么在Query服务中Repository同时有存储查找的职能.或者在此时不再使用Repository这个,而是Finder之类的可能更合适.

ParentRepository

是否需要ParentRepository?

读操作

抛开通过Restful接口来准确指定类型的情况下,恐怕需要一个ParentRepository,这时最好配合数据库的表继承来实现

写操作

insert

那么一定要明确指定Repository

update

json格式

一股脑存储json的时候可以使用ParentRepository

Relation

当不同子表有不同字段的时候,需要指定Repository

delete

可以使用ParentRepository

 类似资料: