What is cqrs?
You can find a lot of information on the Internet about this issue. For more information about untouched shoes, see Udi Dahan, grey young, rinat abdullin, dax.net in the garden, and jdon.CommunityRelatedArticle.
For example, the following articles:
1. http://www.cnblogs.com/daxnet/archive/2011/01/06/1929099.html
1. http://www.udidahan.com/2009/12/09/clarified-cqrs/
2. http://www.jdon.com/jivejdon/thread/37891
Here, we will briefly introduce the problem through an image in the "clarified cqrs" document of UDI Dahan:
There are two types of operations on the UI: commands and queries. For example, the five products with the best sales volume are queries, while submitting an order and changing the password are commands. Because most systems only read and write less, and the business logic basically appears at the write end, the separation of query and command allows us to optimize the query independently.
Query)
You can see that the query is not queried through dB, but through a read dB (the cache in it is not necessarily a database, but for convenience, the table in read dB (for convenience, this read dB is regarded as an RDBMS) is specially optimized for the UI. For example, there may be latestproductlistmodel (productid, productname, price, BrandName, addedtime), bestsoldproductlistmodel (productid, productname, totalsold) and other tables, representing the latest product list, respectively, list of products with the best sales volume (they are actually equivalent to the view model ). Latestproductlistmodel has a BrandName field. Note that it is not a brandid. Therefore, you can use SQL statements such as select * from [Table] to query the interface, there may be a few places, but there is basically no join, which is definitely advantageous for the loading speed of the interface (in fact, it is also using space for time ).
Command)
Most of the business logic occurs when writing data. For example, when a user purchases a product and submits an order, we need to verify the inventory and whether the user information order data is valid. From the traditional perspective of DDD, command is similar to Application Service. USER commands (such as submitting orders) are executed in the form of command, and command does not carry business logic, what commands do is: Get related domain objects through repository and call some domain services to execute some operations (the business logic will be kept in the domain model ), then, execute the commit or savechanges method to submit the changes, and then write the relevant data into the write dB (the DB shown in the figure, hereinafter referred to as the write dB ). Note that the query on the UI is read dB rather than write dB.
Domain Model)
This is not much different from the domain model mentioned in Evans's DDD, that is, the heart of software ".
Domain event)
Domain events are very important, not limited to cqrs. I believe some people have encountered the following problems like me:
The account entity (indicating the account) has a balance attribute (indicating the account balance). We generally do not disclose the setter of this attribute, but write some increasebalance (decimal amount) to change the account balance.
Now the problem arises. We want to add an accountlog record when the account changes, but there are thousands of log records, we cannot directly implement the accountlog set into a collection attribute of the account through the one-to-many ORM ing of ORM. Then we need to get accountlogrepository in increasebalance, in this way, there is a way to insert accountlog (from the perspective of DDD, accountlog is not an aggregate root, So there cannot be accountlogrepository, but when the performance is seriously affected, you have to make a trade-off ).
Regardless of whether dependency injection or something is used, in short, the account has already been dependent on repository, which makes the domain object unpure. In addition, if we do not only need to record logs in the future, what about text message notification? ModifySource code? This is also not OCP.
Domain events can solve this problem: As long as a domain event is triggered at the end of the increasebalance () method, then we write an independent eventhandler class to add logs (the framework ensures that eventhandler can be bound with domain events ).
Back to cqrs, because command writes data to write dB, and the UI queries read dB, we need to implement synchronization between the two databases in some way, the solution is already obvious. Write a bunch of eventhandler classes to listen to domain events. For example, we have a command changepricecommand to change the product price. After the command is executed, a class called pricechangedevent will be triggered, so we only need to write a class called pircechangedeventhandler, here, you can synchronize the price information related to read dB with the latest value (this will involve the problem of table structure change in read dB, which will be discussed later ).
Conclusion
The interesting part of cqrs is not only that, but also event sourcing (es), which is often discussed with cqrs.
In general, cqrs looks charming, but in its own practice, it has encountered various problems, especially es, which almost subverts the normal development thinking. For example, after ES is used, the domain model can only be queried by ID. If you want to query a user named "Shui ge", you cannot, because there is no table named "user. I believe most of my friends who are new to es will feel uncomfortable with this. This requires a change in thinking.
In several subsequent articles, I will continue to share the typical problems I encountered during the cqrs practice and the best solutions I can find (I hope there will be better solutions for my children's shoes ). Then, a mini cqrs framework and a bookstore sample project developed based on it are implemented to demonstrate the benefits of cqrs.
This mini-framework and example project will simplify the cqrs that is often discussed, removing things that have a big personal feeling and a large development span, such as es and asynchronous command, at the same time, we will also make some trade-offs for the usual development solutions. For example, we can use a hybrid query of read dB and write dB in the UI as needed (the premise is that the query of write dB is also very simple, for example, only one SELECT statement is required ).
You are welcome to participate in the discussion. If you have any questions, please correct them.