Preface:
After reading the latest "friends", I learned a sentence about "force-fit". The truly outstanding things include: simple, beautiful, and universal.
Recently, CQRS is being studied and used in projects. Of course, to improve CQRS, the project is also being improved step by step.
Comfort
The first article is about simplicity. Of course, simplicity does not refer to the concept of CQRS, instead, it's just the kind of comfort that a beginner will feel when he suddenly comes into contact with the CQ idea while trying to build a shelf.
Tang Miao: Hello! Don't be angry. Angry people will make a warning! Wukong, you are too naughty.
I told you not to litter. Why are you... You see, I haven't said
You threw away the stick! The baby box is a treasure. If you throw it, it will be contaminated.
What if the environment hits the children? Even if you don't get the kids
Flowers, plants, and grass are not correct!
......
Wukong: So I grabbed the fly and squeezed its belly to pull it out and use it again.
Hold his neck with a force, OH --! The entire tongue stretched out!
I will try again --! The whole world is clean. Now everyone understands why
I want to kill him!
When we spend too much time on research concepts, when we want to learn about CQRS through reading second-hand articles, we will encounter Tang Miao's rush to death!
However, when we first try a simple and universal small project with CQ, the whole world is quiet.
Cheap solution
Let's talk about my understanding of CQRS with a "cheap" attitude.
The above is a classic CQRS architecture diagram. I feel like I understand Q. The problem is mainly concentrated on C. According to my understanding: 1. the C end encapsulates the business in reality into the corresponding Command, and submits it to the corresponding CommandHandler for processing through the "appearance mode"; 2. in reality, commands are usually composed of multiple domains. Therefore, in the corresponding CommandHandler, the processing of commands is handled by the corresponding DomainModel. The Repository is shown below, here is the classic DDD, so the question is: 1. describe the final behavior of each Command by concept by a series of events, therefore, the Event generated by each Command will be sustained by EventSource (some suggestions are relational databases or InMemory. I like InMemory ). 2. because a large system often implements asynchronous command processing, the EventSource generated will be asynchronously written to ReadDB, to achieve data consistency (of course, there are many implementation methods here, such as ReadDB itself is NoSql, or it is implemented through the master-slave mode ). My questions: 1.
Is it really necessary to establish EventSource? What are the real application scenarios?In concept, EventSource can last the entire lifecycle of an Event and return to the status of any Event. If EventSource is large, it can be optimized by creating a "snapshot, but do we really need to consider so much in real scenarios? What is the actual solution? 2. After the Event persists, you can roll back to the status of a corresponding Event, but can you roll back some of its Command loops? A rollback Command will still be generated to append the Event to EventSource again, so that the purpose of Event rollback in a certain state is gone, and I hope to have reference. 3. How to control the Event concurrency? For example, if a concurrent Command is generated in the business, it will eventually act on the generated Event. I understand that to solve the concurrency, we need to queue for processing, so I want to put the processing on the Event more appropriate (based on the specific business), is this appropriate? Or what are your better methods?
The above is an understanding and a question. The question is for later articles or garden friends to help answer the question. Let's get back to the question and get started with it.
To understand CQRS, you need to understand the keywords.
C:
Command: all actions except Q can be considered as Command;
Command Bus: Command Bus. All commands will be sent to CommandBus;
Command Handler: each Command will end with the corresponding CommandHandler for processing;
Domain: because the Command must be implemented on the business Model for operations, Domain is the place where the business Command is actually processed;
Event: in the Domain, the business Command is eventually divided into multiple events for the aggregation root;
Repository: persistent Event after Domain distribution and processing;
EventSource: a collection of persistent events, either InMemory or Relational DB;
Event Bus: Similar to CommandBus to load the final state of the Event in synchronous (or asynchronous) mode;
Event Handler: Similar to CommandHandler, which processes the Event most independently;
Read DB: the database state is finally modified to achieve data consistency. Of course, ReadDB can optimize the Q end in NoSql mode;
Message: I do not understand it yet;
Q:
Q-end feels that there is nothing to say, that is, to establish a set of pipelines between the business Query and ReportDB, which can be used to optimize the Query without affecting the entire business logic (those actions on the C-end ). This achieves read/write splitting in the business and code structure.
No code is just a rogue
Finally, we will provide a small Demo as the initial version of CQRS evolution. The subsequent understanding of CQRS and the evolution of its applications will also be published.
Structure:
Is a Web program:
QueryProcess: responsible for processing the Q end, the lower layer to T-SQL, EF to achieve;
DataProcess: responsible for the C-end, which is implemented by EF at the lower layer;
Model: includes CommandModel, ViewModel, DTOModel;
Data: including EF and Repository;
Common: some basic and Common Helper classes.
API: it interacts with the other two systems in Restful mode;
Controller:
[HttpGet] [UserAuthentication] public ActionResult Index (string id) {AccountViewModel vm = new AccountViewModel (); vm. roleList = ServiceLoader. roleQueryProcess. fetchAll (null ). toList (); vm. accountDtoList = ServiceLoader. accountQueryProcess. fetchAllToDto (). toList (); if (! String. IsNullOrEmpty (id) {vm. tag = id;} return View (vm );}
Obtain the corresponding Query through the appearance mode (ServiceLoader;
QueryProcess:
String SQL = string. format (@ "select top {0} ID, RoleName, RoleCode, parentId from Tb_Role a where 1 = 1 {1} and id not in (select top {2} id from Tb_Role where 1 = 1 {1} order by id desc) order by id desc ", PageConfig. showCount, "", PageConfig. showCount * (PageConfig. rolePageNow-1); DataTable queryTable = SqlHelper. getTableText (SQL, null) [0]; string json = JsonConvert. serializeObject (queryTable); return JsonConvert. deserializeObject <List <autoscaling tool. data. tb_Role> (json );
You can use the T-SQL method to Query databases. Of course, Cache can be attached to the Query center;
Command:
Public class RegisterCommand: BaseCommand {public string userName {get; set;} public string password {get; set;} public bool isRemember {get; set ;}}
A simple Command is generated;
[HttpPost] public ActionResult Login (SignInCommand sign) {Tb_Account account = new Tb_Account () {UserName = sign. userName, Password = sign. password}; CommandActionResult commentResult = ServiceFactory. accountService. accountLogin (account); if (commentResult. isOk ){//...}}
The Command is also distributed to the real Handler program (AccountService) through the ServiceFactory reflection in the appearance mode );
Domain:
Public CommandActionResult AccountLogin (Tb_Account account) {try {Tb_Account result = AccountRepository. fetchT (a =>. userName. equals (account. userName) &. password. equals (account. password);} cache {//...}}
Because it is not clear about the true and reasonable use of EventSource, I will directly persistently store the aggregate root of the Command to the DB;
The use and understanding of CQRS is still in its infancy. However, it is still quite comfortable to come into contact with this concept. If it is not perfect, please include it, I also hope that Daniel can give some advice.
Thanks.
Big talk CQRS-simple