当注册者创建一个订单,她可以申请不同数量的座位,并且这些座位类型可以不相同。例如,登记人可要求五个会议座位和三个会前讲习班座位。
架构该应用程序旨在部署到Microsoft Azure。在旅程的那个阶段,应用程序由两个角色组成,一个包含ASP.Net MVC Web应用程序的web角色和一个包含消息处理程序和领域对象的工作角色。应用程序在写端和读端都使用Azure SQL DataBase实例进行数据存储。应用程序使用Azure服务总线来提供其消息传递基础设施。下图展示了这个高级体系结构。
在研究和测试解决方案时,可以在本地运行它,可以使用Azure compute emulator,也可以直接运行MVC web应用程序,并运行承载消息处理程序和领域域对象的控制台应用程序。在本地运行应用程序时,可以使用本地SQL Server Express数据库,并使用一个在SQL Server Express数据库实现的简单的消息传递基础设施。
有关运行应用程序的选项的更多信息,请参见附录1“发布说明”。
模式和概念本节介绍了在团队旅程的当前阶段,应用程序的一些关键地方,并介绍了团队在处理这些地方时遇到的一些挑战。
记录定位器该系统使用访问码而不是密码,这样注册者就不会被迫在该系统中设置帐户。许多注册者可能只使用系统一次,因此不需要创建一个带有用户ID和密码的永久帐户。
系统需要能够根据注册者的电子邮件地址和访问代码快速检索订单信息。为了提供最低程度的安全性,系统生成的访问代码不应该是可预测的,注册者可以检索的订单信息不应该包含任何敏感信息。
在读端查询数据前一章重点介绍了写端模型及其实现,在本章中,我们将更详细地探讨读端的实现。特别地,我们将解释如何从MVC控制器实现读取模型和查询机制。
在对CQRS模式的初步研究中,团队决定使用数据库中的SQL视图作为读取端MVC控制器查询数据的基础数据源。为了最小化读端查询必须执行的工作,这些SQL视图提供了数据的反规范化(denormalised)版本。这些视图目前与写模型使用的规范化(normalized)表存在同一个数据库中。
Jana(软件架构师)发言:
该团队将把数据库分为两个部分,并在旅程的后期将探索其他的选择来从规范化的写端推送数据到反规范化的读端。有关使用Azure blob存储而不是SQL表存储读取端数据的示例,请参见SeatAssignmentsViewModelGenerator类。
存储读端数据的一个常见选项是使用一组关系数据库表来保存。您应该优化读取端以实现快速读取,因此存储规范化数据通常没有任何好处,因为这将需要复杂的查询来为客户端构造数据。这意味着读取端的目标应该是使查询尽可能简单,并以能够快速有效地读取的方式在数据库中构建表。
Gary(CQRS专家)发言:
当人们选择使用CQRS模式时,可伸缩的应用程序和响应式UI通常是明确的目标。优化读端以提供对查询的快速响应,同时保持资源利用率较低,这将帮助您实现这些目标。
Jana(软件架构师)发言:
由于表连接操作过多,规范化数据库模式可能无法提供足够快的响应时间。尽管关系数据库技术有所进步,但是与单表读取相比,JOIN操作仍然非常昂贵。
译者注:读取端/查询端通常就是所说的前端UI,如果使用关系型数据库的关系表来存储UI层要展现的页面数据。每次读取都需要做连接查询或多次查询。所以把读取端需要的数据保存为反规范的数据可以实现快速读取。这个反规范化(denormalised)可以简单理解为,抛弃关系型数据库的关系,存储非关系型的数据。
一个需要重要考虑的地方就是读取端用来查询数据的接口。读取端就如ASP.Net MVC程序Controller的Action里发起的查询请求。
在下图中,读取端(如MVC Controller里的Action)调用ViewRepository类上的方法来请求它需要的数据。然后,ViewRepository类对数据库中的非规范化数据运行查询。