The CQRS pattern allows us to write more maintainable and scalable code, while also providing a separation of concerns between our read and write operations.

Overview

In our first implementation of the CQRS pattern, we focused on creating a Command service to handle all write operations. This service accepts commands, such as creating new items or updating existing items, and performs the necessary actions on the domain model. The Command service acts as a “black box”, allowing the clients to focus on the business rules rather than the underlying implementation details.

To complement the Command service, we also created a Viewer service to handle read operations. This service exposes a read-only API, allowing clients to retrieve data from the domain model without performing any write operations. The Viewer service ensures that the state of the domain model is always consistent and up-to-date.

By separating the read and write operations using the CQRS pattern, we were able to streamline our code and achieve a clean separation of concerns. The Command service focused on handling the business rules, while the Viewer service provided a mechanism for clients to consume the data.

In our implementation, we used an ORM (Object-Relational Mapping) tool to automatically map the commands to the domain model and to generate the necessary queries to retrieve the data from the domain model. This allowed us to focus on writing the business logic without the need for manual SQL queries or data manipulation.

What is CQRS?

CQRS stands for Command and Query Responsibility Segregation. The idea behind this pattern is to have completely separate models for reading and writing data.

Note:

Be aware that I said model, not necessarily different databases.

This idea is indeed a shift away from the well known single data model scenario in crowd systems where we do both read and write operations.

The reason why this pattern is quite useful is because no database technology is optimized to be great at both reads and writes.

For example, have you ever tried to implement graph structure such as nodes and edges in a relational database? I surely have and that didn’t go well.

In CQRS, commands describe actions that change the data.

As a result, they modify the state of a system. So they have side effects.

On the other hand, queries returned data and don’t modify the state of the system. For that reason, they don’t have any side effects and are idempotent.

In other words, it doesn’t matter how many times you execute a query. The result will be the same.

Let’s dive deeper into this pattern.

Solution 1:

Commands should be validated before they’re applied to the model.

For example, in the Wisdom Pet Medicine solution, we receive the commands as part of the HTTP requests payload. Then we handle the command in the application service which in turn involves the domain model logic to attempt to apply the given command and finally restore the setback to the database.

Queries are completely separate functionality and they don’t depend on domain knowledge.

They’re just a way to get the data out from the database. For this reason we could use different technology stacks if we want to.

For example in the Wisdom Pet Medicine solution we’ll use dapper, a lightweight ORM framework that allows us to execute any query without hassle.

Of course, we don’t even need an ORM for that matter. The point here is that with CQRS, you can escape from overly complex single models with poor performance and cumbersome design.

 As you can see in this diagram, both commands and queries are using a single database.

Take into account that queries could return DTLs or dynamically created structures. In this course, we’re going to use the latter. Now, we could implement the command and query parts as separate

microservices,

or we could implement them in the same microservice.

That decision will depend on the particular business requirements that you have.

Solution 2:

You can achieve greater isolation if you physically separate the read data from the write data.

Also you could take advantage of having different data storage technologies. In that sense, you could have an optimized data store for queries.

Challenge:

The challenge in this scenario is how can we synchronize the data from write model to the read model?

Well, there are different ways to do that but generally speaking, you need some kind of event or message.

Another option could be that the command is responsible for writing in both databases.

However, I think that could negatively impact the performance and scalability.

Note:

In this post, we’ll use the Azure Cosmos DB change feed when dealing with CQRS and two separate databases.

As I’ve already mentioned, you could implement each part in a separate microservice or you could implement them as a single one.

Benefits of CQRS:

Having the ability to use different data models for writes and reads is clearly a significant benefit.

It’s one could take advantage of the underlying data storage technology to optimize its model.

Scalability is enhanced because we could scale each microservice independently.

In most systems, the number of read operations exceeds the number of write operations.

Finally the code is more maintainable because all the logic is implemented in the write model.

And we can project any kind of data structure from the read model.

Implement the First Command

In this section, we’ll deal with the command part of the CQRS pattern.

First, we’ll add a new value object named AdopterPhoneNumber.

Then we’re going to create a new property in the adopter entity named phone number of type AdopterPhoneNumber.

Since we don’t want to allow external domain models or systems to modify the state of an entity object directly, we’re going to expose a public method named SetPhoneNumber.

In addition to that, we’re going to modify the state validation logic of the adopter entity to prevent invalid phone numbers, at least in terms of a string length.

Next we’ll create a new class named SetAdopterPhoneNumber command in the Rescue API project.

After that we’ll modify the AdopterApplicationService class to add a new method for handling the SetAdopterPhoneNumber command.

The AdopterController will initially receive the command as part of the HTTP request, which in turn uses the newer handler that we’ll implement.

Finally, we’ll modify the RescueDbContext, to tell entity framework core, to find in the structure of the adopter entity we’re in persisting it. Okay.

Let’s get started.

So here in Visual Studio, I’m going to add a new class inside the value objects folder.

And this is going to be AdopterPhoneNumber, and we’re going to use record instead of class, because this is a nice addition to the C# language that allows us to compare objects based on their values.

I’m going to create a new constructor that takes the phone number, and this is going to be internal because I just want to create this AdopterPhoneNumber objects inside the domain model.

And of course, we need another way to create this kind of objects outside the domain model.

So I’m going to create another method here that takes the phone number and these returns a new AdopterPhoneNumber object.

Excellent.

We need also some kind of property to expose the value, but this time, I’m going to make this property as init.

So it becomes immutable after initializing. So I can do that.

And finally, I want to create a new validation method that I already have here.

So as you can see, I’m validating that the PhoneNumber is not null and the length is less or equals to 15, and I’m going to invoke this validate method right here.

And we’re good to go.

Now we need to modify the adopter entity because I want to expose the AdopterPhoneNumber type.

This is going to be PhoneNumber and private set, because I don’t want to modify this properties or the state of the entity outside of the domain model.

Excellent. Next, we’re going to modify this, validate a state for adoption method, because I want to validate if the PhoneNumber equals null, then I’m going to throw a new InvalidAdopterStateException, and let’s say phone number is missing. And we’re good to go.

Now let’s open the Rescue API project because we need to create the command right here.

I’m going to create the SetAdopterPhoneNumber command, and this will expose a couple of properties.

The first one is the adopter ID.

The second one is the phone number itself. Let’s name it, PhoneNumber, just like that.

So let’s modify the AdopterApplicationService class because we need to receive the command object right here.

I’m going to copy this and I’m going to replace this command with SetAdopterPhoneNumber command. Of course, we need to obtain the state of the adopter, then we’re going to use the SetAdopterPhoneNumber that actually we didn’t implement.

So let’s go back to the adopter entity and let’s add a new public void SetPhoneNumber that takes AdopterPhoneNumber and we’re going to set phone number equals phone number.

And we can go back here. Let’s rename this because this is ID instead of adopter ID. And we can use this SetPhoneNumber method that takes the phone number value. Of course we need PhoneNumber.Create, command phone number, and we’re persisting the state back to the database. So as you can see, it’s very easy to handle this command.

And of course, we need another method in the controller.

Let’s go to the controller, and I’m going to copy this, let’s name, this segment as phonenumber and let’s use HttpPut, and this takes SetAdopterPhoneNumber command, and basically that’s it. Let’s move this to this position after the requestAdoption command.

And we’re good to go.

Actually, we can now test this, but before we do that, we need to modify the RescueDbContext right here, because we need to flatten the structure.

We need to tell entity framework core that the phone number is part of the same table. So I’m going to copy this and I’m going to use PhoneNumber.

And of course we need to delete the rescue database because otherwise, this is not going to recreate the database.

Remember that we’re not using EF Core migrations.

So let’s go to SQL Server Management Studio. And right here, I’m going to drop this database, rescue, okay, close existing connections.

And let’s go back to visual studio. And now we’re ready to test this.

So let’s start a new debugging session, it looks like it has some problems with my port.

So let’s change the port right here. I’m going to change it to this other port.

Let’s try it again.

As you can see, this is running.

So let’s go back to SQL Server Management Studio to see if the database was created.

So here’s the database, and of course we need to create a new adopter.

So let’s go back to the Swagger UI. So here, I’m going to create a new adopter.

Let’s click on execute, actually the values doesn’t matter right now, I’m going to click on execute and let’s go back to SQL server.

And right here, I’m going to right-click and select top 1000 rows. As you can see, we have the new adopter right here.

So now, we’re ready to modify the phone number, which is null in this moment.

So let’s go back to Swagger and right here, I’m going to select this other endpoint and try it out.

And let’s say clause one, two, three, four, five, six, seven, eight, nine, or something like that. Execute. Let’s go back to SQL server and let’s click again on execute.

And as you can see, the phone number has changed.

Good job! Now we’re ready to implement the query part.

Implement the Viewer Service

We’ve gone through the command part of the CQRS pattern already.

Now it’s time to implement the query part.

Let’s see how we can do that.

In this section, we’ll add a new RescueQuery microservice.

The reason why this is a separate API is because after the event storming session with Wisdom Pet Medicine’s domain experts, we detected that external systems will heavily use this API.

Therefore, we could scale this microservice independently.

We could also modify it independently if that were necessary. we’ll use Dapper to query the database and project a different view model freely.

Remember that these kind of queries most of the time are meant to be used in user interfaces, reports and so on.

For this reason, it’s nice to have different models for both commands and queries.

Okay let’s move on. So here in Visual Studio, I’m going to create a new project inside the Rescue folder, and let’s use this ASP.NET Core web application template. Let’s put this inside the source folder and we’re going to name this project as WisdomPetMedicine.RescueQuery.api and let’s click on Create. Excellent. Now, the first thing that we need to do is to delete this weather forecast class because that comes from the template, but actually we’re not going to use that class. And let’s rename this WeatherForecastController class to RescueQueryController. RescueQueryController.

Excellent and let’s get rid of everything.

Now we need to add a reference to Dapper. So let’s manage the new get packages and let’s search for Dapper. Let’s install that.

And also we need the Microsoft Data SQL Client package because we’re going to use the SQL Connection object.

Done. Excellent.

Let’s go back to the RescueQueryController class and there we’re going to add a new constructor and we’re going to inject the IConfiguration object.

Let’s put that inside a field. And now we’re ready to implement the endpoint.

For instance, I’m going to use task of IActionResult and let’s name this Get or something like that and we’re going to use the HTTP GET attribute.

Excellent.

Now we’re ready to write the query that we want to execute.

Since we’re using Dapper, we’re free to write any kind of query we need.

I don’t want you to see me typing so I have the query already and I’m going to paste it As you can see, I’m using some T-SQL sentences such as case to project different columns. And also as you can see, we’re using the rescued animals metadata, the rescued animals table and also the adopters table.

So let’s solve this namespace and also the QueryAsync namespace and we’re good to go. Before we test this microservice, we need the connection string.

So let’s edit this app setting’s JSON and we need the connection strings subsection and we’re going to type the connection string.

Actually we have that already in place.

So let’s open the app settings JSON file from the Rescue API project.

Let’s copy this.

Let’s go back and paste it right here.

Done.

Finally, we need to be sure that this new project gets executed.

So let’s right click here in the solution, set startup projects and here the RescueQuery API.

We’re going to set it as start.

Done.

Let’s click on the Start Debugging Session and let’s go to the swagger UI.

So here, I’m going to click on the GET button, try it out, execute.

And this is returning 200. However, we’re not receiving any results. That’s because I deleted the database.

So let’s go to the swagger UI of the pet microservice.

Now we’re going to flag the pet for adoption. Done and let’s go to the swagger UI of the rescue microservice.

Here I’m going to request to adopt that pet and now we can go back to the RescueQuery API.

Let’s try this again.

Try it out, execute.

And now we’re receiving the projected data that comes from this rescued animals metadata, rescued animals and adopters.

Conclusion

With this pattern, we explored how to use the Command and Query Responsibility Segregation (CQRS) pattern and write our first Command and Viewer service. The CQRS pattern allows us to separate the read and write operations of our system, allowing for a more efficient and scalable architecture.

Happy Coding!

Leave a Reply

Discover more from Rajeev Singh | Coder, Blogger, YouTuber

Subscribe now to keep reading and get access to the full archive.

Continue reading