Java 域逻辑-读取模型

Java 域逻辑-读取模型,java,c#,domain-driven-design,cqrs,event-sourcing,Java,C#,Domain Driven Design,Cqrs,Event Sourcing,我有两个问题 Person { private personID personID; private nodeID nodeID; //belongs to node } Node { private nodeID nodeID; //node's id private nodeID parent; //parent node reference by id public void assign(Person person); } 现在我有了我的人员分

我有两个问题

Person {
    private personID personID;
    private nodeID nodeID; //belongs to node
}
Node {
    private nodeID nodeID; //node's id
    private nodeID parent; //parent node reference by id

    public void assign(Person person);
}
现在我有了我的人员分配服务的域逻辑: 只有当某人属于节点
“Y”
时,才能将其分配到节点
“X”
,该节点是父母或曾祖父或曾祖父或。。。节点
“X”

要找到它,我需要查询
阅读Model
。 我在域中,所以我不能只使用我的读取模型来查询它。 我不认为我可以仅仅将ConnectiontoRead模型添加到我的存储库中,因为它连接到我的事件存储。特别是,当
读取模型时
可以放在另一台服务器上,成为另一个应用程序


实现它的正确方法是什么?

正确的方法是在命令模型中支持祖先检查。这是您想要强制执行不变量的地方,因此模型需要支持这一点

如果您需要能够进行无限祖先检查,那么树结构通常会导致性能问题。因此,您可能需要实现一个性能优化来改进这些类型的查询

我认为有以下可能:

  • 使用直接支持所需查询的数据存储。如果你想做ES,这可能很难
  • 使用快照。这可能可行,也可能不可行,这取决于您的树结构
  • 使用缓存。这类似于快照,但将信息存储在缓存中,而不是事件存储中
  • 使用read模型。请确保您了解后果,特别是异步数据传播和增加的复杂性。我只建议作为最后的手段,但YMMV

以下是一个合同:

仅当人员属于节点“Y”时,才能将其分配到节点“X” 哪一个是父母、曾祖父、曾曾祖父或。。。 节点“X”的位置


如果这是一个必须强制执行的约束,您可以在写端(例如,
Graph
)的单独聚合中对层次结构建模,其唯一目的是确保完整性。

谢谢您的回答。在我的整个应用程序中,我只有一个地方有这样的逻辑。因此,我不会离开我的活动商店,因为这一点。老实说,我真的不明白快照或缓存在这种情况下有什么帮助。我将快照/缓存域中的单个聚合。我需要写的是递归查询,来找到我想要的结果。这个想法很有趣。所以,每当我添加新节点或编辑现有节点时,我都应该更新图形,对吗?但这样的聚合将毫无逻辑可言,它的目的是将我作为域内的读取模型。这不是太多了吗?聚合是层次结构的唯一真相来源,而不是读取模型。一致性逻辑是该聚合的逻辑。读取模型只是一个抽象,您可以在您的域中使用它。CQRS是一个如何对业务用例建模的设计原则,它不是一个有两个分开的bucket的规则。事实上,CQR应用于一个有界上下文,即模型的一部分用于更改业务状态(命令),而其他部分则不会更改任何内容(查询)。我明白,读和写是在同一个有界上下文中进行的。但问题在于技术层面。我不能只是查询Read模型并在那里查找我的聚合,因为聚合这样的东西不存在于这一边。读取模型保存非规范化数据,因此我无法从中构建事件源聚合。什么负责查询读取模型、存储库?或者某种抽象,实际上会向读取模型的RESTAPI发送请求?您不使用RM查询聚合,只是为了获取业务决策所需的数据。我的观点是,你的聚合试图做的太多了,你应该只使用它来改变一个概念状态,而不是所有与一个概念相关的东西。对于业务查询,您拥有根据业务规则解释现有状态(读取模型)的域服务。聚合的目的只是强制执行业务约束,以保持概念的有效性/一致性,所有其他行为都属于域服务。因此,以这种方式实现它是完全可行的吗?PersonalSigningService->将保护分配与聚合本身无关的不变量,并将使用PersonalLowedToAsignToNodes策略(不能使用更好的名称atm:),策略将是接口。此策略的实现将查询RM Rest API以获取必要的信息。我的意思是,您应该在该服务器上也有一个读取模型,用于本地查询。因此,在“命令”服务器上有一个RM(可能更具体、更定制),在“查询”服务器上有另一个RM。是的,这意味着RM复制(实际上,只是在两台服务器上使用相同的库),但也意味着您的服务器不耦合,性能不会受到影响。这算是一种交易。