在CQRS架构中,一个比较重要的内容就是当命令处理器从命令队列中接收到相关的命令数据后,通过调用领域对象逻辑,然后将当前事件的对象数据持久化到事件存储中。主要的用途是能够快速持久化对象此次的状态,另外也可以通过未来最终一致性的需求,通过事件数据将对象还原到一个特定的状态,这个状态通常是通过对象事件的版本来进行还原的。

要实现一个事件存储的框架,我们通常需要实现以下几个方面:

1.对象事件的存储表

我们通常将对象某个变化的事件数据存储到数据库的表中,通常采用关系型数据库进行存储,这里使用SQL Server。

AggregationRootId是当前聚合根对象的Id;AssemblyQualifiedAggreateRooType是当前聚合根对象的FQDN名,在C#代码中对应名称空间+类名(例如:Order.Domain.POCOModels.Orders, Order.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null);AssemblyQualifiedCommandAndEventType是操作当前聚合根的事件类型的FQDN名字,在C#代码中对应名称空间+类名(例如:Events.OrderCommands.CreateOrderCommand, Events, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null),Version对应的是针对某个聚合根当前事件操作的版本,通常对一个聚合根进行操作,版本就加1,Data则包括当前事件操作后,对象的当前状态数据。

2.重构Event用以支持存储

前面文章实现的事件只是用于标识消息,在事件需要存储时,我们需要更多的属性,包括聚合根ID,聚合根类型,操作聚合根的事件类型,版本号等。

public interface IEvent

{Guid Id { get; set; }DateTime CreateDate { get; set; }Guid AggregationRootId { get; set; }string AssemblyQualifiedAggreateRooType { get; set; }string AssemblyQualifiedCommandAndEventType { get; set; }int Version { get; set; }
}

public class BaseEvent : IEvent

{public Guid Id { get; set; }public DateTime CreateDate { get; set; }public Guid AggregationRootId { get; set; }public string AssemblyQualifiedAggreateRooType { get; set; }public string AssemblyQualifiedCommandAndEventType { get; set; }public int Version { get; set; }public BaseEvent(){this.Id = Guid.NewGuid();this.CreateDate = DateTime.Now;}
}

3.实现存储的事件对象

其实这里要实现的就是将事件和事件对象之间做相互的转换,用于未来存储事件或将事件反序列化成事件对象进行使用。

public class EventObject:BaseEvent

{        public byte[] Data { get; set; }public static EventObject FromDomainEvent(IEvent idomainevent){var domaineventobject = new EventObject();domaineventobject.Id = idomainevent.Id;domaineventobject.CreateDate = idomainevent.CreateDate;domaineventobject.Version = idomainevent.Version;domaineventobject.AggregationRootId = idomainevent.AggregationRootId;domaineventobject.AssemblyQualifiedAggreateRooType = idomainevent.AssemblyQualifiedAggreateRooType;domaineventobject.AssemblyQualifiedCommandAndEventType = idomainevent.AssemblyQualifiedCommandAndEventType;domaineventobject.Data = XmlObjectSerializer.Serialize(idomainevent);return domaineventobject;}public  IEvent ToDomainEvent(){            Type type = Type.GetType(this.AssemblyQualifiedAggreateRooType);var domainevent = (IEvent)XmlObjectSerializer.Deserialize(type, this.Data);domainevent.Id = this.Id;return domainevent;}
}

FromDomainEvent方法就是将事件信息转换为以后要存储的事件对象,ToDomainEvent就是将事件对象转换为事件。

4.实现事件存储

实现事件存储就是将领域事件对象存储到我们前面创建的数据库表中。为了能够快速存储,我们并不采用ORM框架,而是直接使用ADO.NET完成事件对象的存储。

public void SaveEvent(IEvent idomainevent)

    {try{var domaineventobject = EventObject.FromDomainEvent(idomainevent);conn.Open();SqlParameter sqlparm = new SqlParameter("@AggregationRootId", System.Data.SqlDbType.UniqueIdentifier);sqlparm.Value = idomainevent.AggregationRootId;cmd =new SqlCommand("select count(*) from DomainCommandAndEventObject where AggregationRootId=@AggregationRootId", conn);cmd.Parameters.Add(sqlparm);var count = cmd.ExecuteScalar();if(count!=null){domaineventobject.Version = int.Parse(count.ToString());}SqlParameter[] sqlparams = new SqlParameter[7];sqlparams[0] = new SqlParameter("@Id", System.Data.SqlDbType.UniqueIdentifier);sqlparams[0].Value = domaineventobject.Id;sqlparams[1] = new SqlParameter("@AggregationRootId", System.Data.SqlDbType.UniqueIdentifier);sqlparams[1].Value = domaineventobject.AggregationRootId;sqlparams[2] = new SqlParameter("@AssemblyQualifiedAggreateRooType", System.Data.SqlDbType.NVarChar);sqlparams[2].Value = domaineventobject.AssemblyQualifiedAggreateRooType;sqlparams[3] = new SqlParameter("@AssemblyQualifiedCommandAndEventType", System.Data.SqlDbType.NVarChar);sqlparams[3].Value = domaineventobject.AssemblyQualifiedCommandAndEventType;sqlparams[4] = new SqlParameter("@CreateDate", System.Data.SqlDbType.DateTime);sqlparams[4].Value = domaineventobject.CreateDate;sqlparams[5] = new SqlParameter("@Version", System.Data.SqlDbType.Int);sqlparams[5].Value = domaineventobject.Version;sqlparams[6] = new SqlParameter("@Data", System.Data.SqlDbType.VarBinary);sqlparams[6].Value = domaineventobject.Data;cmd = new SqlCommand("insert DomainCommandAndEventObject values(@Id,@AggregationRootId,@AssemblyQualifiedAggreateRooType,@AssemblyQualifiedCommandAndEventType,@CreateDate,@Version,@Data)", conn);foreach(var sqlparam in sqlparams){cmd.Parameters.Add(sqlparam);}cmd.ExecuteNonQuery();}catch(Exception error){throw error;}finally{cmd.Dispose();conn.Close();}

这样,我们基本就实现了事件与存储方面的基础内容。

QQ讨论群:309287205
微服务实战视频请关注微信公众号:MSSHCJ

微服务实战(六):落地微服务架构到直销系统(事件存储)相关推荐

  1. 微服务实战(五):落地微服务架构到直销系统(构建高性能大并发系统)

    在现代系统中,特别是互联网软件,通常会涉及到大量用户的并发访问,我们的系统一定要在架构上支持高性能.大并发的访问.一个高性能的系统通常由很多的方面组成,包括数据库高性能.Web服务器高性能.负载均衡. ...

  2. 基于微服务架构的餐饮系统的设计与实现计算机毕业设计源码86393

    摘    要 近年来,我国经济和社会发展迅速,人们物质生活水平日渐提高,餐饮行业更是发展迅速,人们对于餐饮行业的认识和要求也越来越高.传统形式的餐饮行业都是以人为本,管理起来需要很多人力.物力.财力, ...

  3. SpringCloud Alibaba微服务实战(六) - 路由网关(Gateway)

    什么是 Spring Cloud Gateway? Spring Cloud Gateway 是 Spring 官方基于 Spring 5.0,Spring Boot 2.0 和 Project Re ...

  4. 实战落地微服务架构商城项目-part01

    文章目录 分布式三高商城系统 一.系统架构演变 1.服务架构的演变 1.1单体架构 1.2集群 1.3垂直化 1.4服务化 1.5微服务化 微服务和SOA的区别 2.微服务架构的需求 2.1RPC框架 ...

  5. 仿百度网盘的一款轻量级微服务架构网盘系统

    Java面试笔试面经.Java技术每天学习一点 公众号Java面试 关注我不迷路 作者:996学院 来源:https://gitee.com/college996/zwz-netdisk 一.前言 在 ...

  6. 基于 SpringCloud 微服务架构的广告系统(第一部分:eureka、zuul、通用模块)

    目录 广告系统架构图 一.eureka服务 二.zuul网关 zuul启动与自定义过滤器(实现访问记录)示意图 三.通用模块(统一响应与统一异常) 统一响应(对象)示意图 统一响应示意图 统一异常(对 ...

  7. 一款轻量级微服务架构网盘系统,你Get了吗

    一.前言 在gitee和github里面基本上找不到一款好用.功能完善.且开放源码的网盘系统,有一些可以免费试用但是只提供安装包,于是在利用业务时间开发了一套轻量级且易于上手的网盘系统,主要基于目前主 ...

  8. 监控即服务:微服务架构的模块化系统

    除了单体应用的代码,我们的项目还由几十个微服务组成.这些微服务都需要加以监控,而这些事情全部让 DevOps 工程师来做是不太可能的.所以我们开发了一个监控系统,为开发者提供服务.他们可以自由的配置监 ...

  9. 11.落地:微服务架构灰度发布方案

    前置知识 1.nacos 服务注册与发现 2.本地负载均衡器算法 3.gateway 网关 4.ThreadLocal 1.什么是灰度发布? 2.什么是灰度策略? 3.灰度发布落地方案有哪些 4.灰度 ...

最新文章

  1. jquery对事件的监听方法addEventListener()
  2. SQLite数据库Java驱动下载及连接示例(sqlite-jdbc-3.30.1.jar)
  3. LCD 常用的客观效果指标和测试方法
  4. C#开发VS LUA开发
  5. [高效时间管理]复盘篇
  6. 运用循环判断语句和列表的购物车程序
  7. Asp.net导出Excel报表(解决无网格问题)
  8. 从生产线到生产岛:理解敏捷开发中的设计与测试活动
  9. R实现地理位置与经纬度相互转换
  10. 504 Gateway Time-out 和 502 Bad Gateway相关处理
  11. 常见Linux发行版本(转载)
  12. 人力资源管理数据分析
  13. 字段缩写ti表示什么_EBSCOhost数据库中,检索字段代码为TI、SO、AU分别表示
  14. 计算机切换用户界面键,电脑如何切换屏幕_电脑怎么切换另一个界面快捷键
  15. Xilinx HLS基础介绍(一)——HLS概念以及接口管理
  16. C# 添加水印图片、文字、缩略图处理
  17. Java Spring MVC框架 VIII 之 Spring MVC拦截器
  18. zigbee设备类型
  19. 别找了,这就是你想要的年会抽奖开源项目
  20. 【友情链接NO.0000?】大佬们的博客(°ー°〃)

热门文章

  1. c++ stl队列初始化_声明,初始化和访问向量| C ++ STL
  2. ubuntu路由器联网_路由器及其协议简介| 联网
  3. python掷骰子_用于掷骰子的Python程序(2人骰子游戏)
  4. eclipse中图片大小用什么单位_建筑工程行业中各个单位都是什么样的关系?
  5. 如果年轻,就出发吧!
  6. ubuntu18重装笔记
  7. golang json判断类型
  8. visual studio 2015 配置好qt5后, 第一次运行出现 无法打开源文件“QtWidgets/QApplication”和无法运行rc.exe的解决方案
  9. Linux内核驱动之GPIO子系统(一)GPIO的使用
  10. IDEA快速修改类名和文件名