C# 在哪个项目中,应使用事件源实时读取DDD中的模型(预测)?

C# 在哪个项目中,应使用事件源实时读取DDD中的模型(预测)?,c#,domain-driven-design,cqrs,event-sourcing,C#,Domain Driven Design,Cqrs,Event Sourcing,在典型的DDD体系结构中,我们有3个项目: 域-无引用 应用程序-它引用了域项目 基础设施-它参考了域项目 (+Web/UI项目) 域模型当然存在于域项目中。但在哪个项目中应该为读取数据库提供实时读取模型(投影),例如MongoDb?简短回答,应用程序服务(应用程序层)和存储库(基础设施层)都知道读取模型。域层对底层持久性和加载机制保持透明 答案很长,确切的使用机制取决于您如何使用read模型。您可以使用它们来构造域层中使用的对象,或者更典型地,仅作为对API查询的响应 第一种情况:将读取模型用

在典型的DDD体系结构中,我们有3个项目:

-无引用

应用程序-它引用了域项目

基础设施-它参考了域项目

(+Web/UI项目)


域模型当然存在于域项目中。但在哪个项目中应该为读取数据库提供实时读取模型(投影),例如MongoDb?

简短回答,应用程序服务(应用程序层)和存储库(基础设施层)都知道读取模型。域层对底层持久性和加载机制保持透明

答案很长,确切的使用机制取决于您如何使用read模型。您可以使用它们来构造域层中使用的对象,或者更典型地,仅作为对API查询的响应

第一种情况:将读取模型用作域层中的对象

应用程序服务将读取模型从存储库加载到域实体中。存储库负责将读取模型正确地填充到域实体中。存储库还负责将域实体转换为写入模型,以在主数据库中持久化

当您到达域模型时,对象已经在存储库的帮助下加载到内存中。因此,域层甚至不知道读模型和写模型;它只处理域实体

第二种情况:使用读取模型存储对API查询的预构建响应

这个场景是读取模型的一个更典型的用法。通常,同一实体/聚合有多个读取模型,因为它们是为特定API请求定制的


在这种情况下,我们甚至不接触域层。应用程序服务接受请求,使用读取模型存储库加载对象,并向应用程序服务器返回响应。

老实说,这并不重要。面向DDD的实现或面向事件源的实现都没有默认结构

如果系统很小,您完全可以拥有单个项目。如果你想保持你的域没有外部引用,你可以把它放在一个单独的项目中,并且除了你需要支持域模型基础的东西,比如实体基类等等,注意不要有任何引用

读取模型和投影与域模型完全正交,通常查询API或查询服务需要它们。将读取模型(MongoDB中的文档)和投影保存在一个位置将使您受益匪浅。您可以从API项目中引用此项目,也可以将查询API、查询服务、查询模型、读取模型和投影放在一起

同样,我认为“典型的DDD体系结构”这样的东西是不存在的,因为DDD不是一开始的体系结构。拆分项目更多的是开发人员的便利和纪律问题,拆分系统是架构问题,而不是DDD特有的


我想到的一件事是,如果你真的考虑DDD,你可能首先想知道什么是你的上下文映射,你真正需要多少域模型,也许在那里你可以找到一些关于分离的想法,实际上并不是基于技术问题。

没有成文法律规定read模型应该存在于哪个项目中。在我个人看来,我认为有一个单独的阅读模型项目有它的好处。对于命令查询,如果应用程序的命令部分可以访问应用程序的查询部分,那么事情就会变得非常混乱。我认为两者应该明确分开

我花了一些时间在一个示例项目上,该项目演示了如何设置DDD/端口和适配器/CQRS应用程序。我已删除GitHub上的代码:

我还花了一些时间在以下文章中详细解释了我所做的选择:

  • 以及
希望有帮助


Cheers

在事件源中,读取模型不代表定义的域实体。真相的唯一来源是那个实体的事件流。好的观点,@AlexeyZimarev。我应该提到的是数据的中间快照,从事件流捕获。即使如此,您说的读取模型在域层中不起作用也是正确的。我可以想象您使用读取模型作为某些域服务的数据源。这可能并不理想,但仍然合法。也就是说,我会尽量避免使用read模型作为任何类型信息的主要来源来在域中做出决策。实体或集合需要包含足够的信息才能做出决策。同意。到目前为止,在我的所有实现中,read模型只用于预先准备好的API响应。通常,同一实体或聚合有多个读取模型。正如我在回复中强调的,在第一种情况下使用read模型不是一种典型的情况,尽管这是可能的。所以我们的思维过程是同步的。