One of the more important things in the CQRS architecture is that when the command processor receives the relevant command data from the command queue, it invokes the realm object logic and then persists the object data for the current event into the event store. The main purpose is to be able to quickly persist the state of the object, in addition to the future through the final consistency of the requirements, through the event data to restore the object to a specific state, which is usually through the version of the object event to restore.
To implement a framework for event storage, we often need to implement the following aspects:
1. Storage table for object events
We typically store an object's changed event data in a table in the database, usually in a relational database, where SQL Server is used.
CREATE TABLE [dbo]. [Domaincommandandeventobject] ([Id] [uniqueidentifier] null,[aggregationrootid] [uniqueidentifier] null,[assemblyqualifiedaggreaterootype] [ NVARCHAR] (null,[assemblyqualifiedcommandandeventtype) [nvarchar] (a) null,[createdate] [datetime] null,[ Version] [int] null,[data] [varbinary] (max) NULL)
Aggregationrootid is the current aggregate root object's id;assemblyqualifiedaggreaterootype is the FQDN name of the current aggregate root object, corresponding to the namespace + class name in C # code ( Example: Order.Domain.POCOModels.Orders, Order.domain, version=1.0.0.0, Culture=neutral, Publickeytoken=null) Assemblyqualifiedcommandandeventtype is the FQDN name of the event type that operates the current aggregate root, corresponding to the namespace + class name in C # code ( For example: Events.OrderCommands.CreateOrderCommand, Events, version=1.0.0.0, Culture=neutral, Publickeytoken=null), Version corresponds to the current event action for an aggregate root, typically operates on an aggregate root, and the version adds 1,data to include the current state data of the object after the current event operation.
2. Refactoring event to support storage
The events implemented in the previous article are only used to identify messages, and we need more properties when the event needs to be stored, including aggregate root IDs, aggregate root types, event types that manipulate aggregate roots, version numbers, and so on.
Public InterfaceIEvent {Guid Id {Get;Set; } DateTime CreateDate {Get;Set; } Guid Aggregationrootid {Get;Set; } stringAssemblyqualifiedaggreaterootype {Get;Set; } stringAssemblyqualifiedcommandandeventtype {Get;Set; } intVersion {Get;Set; } }
Public classbaseevent:ievent { PublicGuid Id {Get;Set; } PublicDateTime CreateDate {Get;Set; } PublicGuid Aggregationrootid {Get;Set; } Public stringAssemblyqualifiedaggreaterootype {Get;Set; } Public stringAssemblyqualifiedcommandandeventtype {Get;Set; } Public intVersion {Get;Set; } Publicbaseevent () { This. Id =Guid.NewGuid (); This. CreateDate =DateTime.Now; } }
3. Implementing the Stored Event object
The thing to do here is to convert events and event objects to each other, to store events in the future, or to deserialize events into event objects for use.
Public classeventobject:baseevent { Public byte[] Data {Get;Set; } Public Staticeventobject fromdomainevent (IEvent idomainevent) {varDomaineventobject =NewEventObject (); 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); returnDomaineventobject; } PublicIEvent todomainevent () {Type type= Type.GetType ( This. Assemblyqualifiedaggreaterootype); varDomainevent = (IEvent) xmlobjectserializer.deserialize (type, This. Data); Domainevent. Id= This. Id; returndomainevent; } }
The Fromdomainevent method is to convert the event information into an event object to be stored later, Todomainevent is to convert the event object to an event.
4. Implementing Event Storage
Implementing the event store is to store the domain event object in the database table that we created earlier. In order to be able to store quickly, we do not use the ORM framework, but instead direct the storage of the event object using ADO.
Public voidsaveevent (IEvent idomainevent) {Try { varDomaineventobject =eventobject.fromdomainevent (idomainevent); Conn. Open (); SqlParameter Sqlparm=NewSqlParameter ("@AggregationRootId", System.Data.SqlDbType.UniqueIdentifier); Sqlparm. Value=idomainevent. Aggregationrootid; CMD=NewSqlCommand ("Select COUNT (*) from Domaincommandandeventobject where aggregationrootid= @AggregationRootId", conn); Cmd. Parameters.Add (Sqlparm); varCount =cmd. ExecuteScalar (); if(count!=NULL) {Domaineventobject. Version=int. Parse (count. ToString ()); } sqlparameter[] Sqlparams=Newsqlparameter[7]; sqlparams[0] =NewSqlParameter ("@Id", System.Data.SqlDbType.UniqueIdentifier); sqlparams[0]. Value =Domaineventobject. Id; sqlparams[1] =NewSqlParameter ("@AggregationRootId", System.Data.SqlDbType.UniqueIdentifier); sqlparams[1]. Value =Domaineventobject. Aggregationrootid; sqlparams[2] =NewSqlParameter ("@AssemblyQualifiedAggreateRooType", System.Data.SqlDbType.NVarChar); sqlparams[2]. Value =Domaineventobject. Assemblyqualifiedaggreaterootype; sqlparams[3] =NewSqlParameter ("@AssemblyQualifiedCommandAndEventType", System.Data.SqlDbType.NVarChar); sqlparams[3]. Value =Domaineventobject. Assemblyqualifiedcommandandeventtype; sqlparams[4] =NewSqlParameter ("@CreateDate", System.Data.SqlDbType.DateTime); sqlparams[4]. Value =Domaineventobject. CreateDate; sqlparams[5] =NewSqlParameter ("@Version", System.Data.SqlDbType.Int); sqlparams[5]. Value =Domaineventobject. Version; sqlparams[6] =NewSqlParameter ("@Data", System.Data.SqlDbType.VarBinary); sqlparams[6]. Value =Domaineventobject. Data; CMD=NewSqlCommand ("Insert Domaincommandandeventobject values
(@Id, @AggregationRootId, @AssemblyQualifiedAggreateRooType, @AssemblyQualifiedCommandAndEventType, @CreateDate, @ Version, @Data)", conn); foreach(varSqlparaminchsqlparams) {cmd. Parameters.Add (Sqlparam); } cmd. ExecuteNonQuery (); } Catch(Exception error) {Throwerror; } finally{cmd. Dispose (); Conn. Close (); }
In this way, we basically implement the event and storage aspects of the basic content.
QQ Discussion Group: 309287205
Micro Service Video Please pay attention to the public number: