CQRS Event Sourcing: Validate UserName uniqueness

Mouhong Lin picture Mouhong Lin · Feb 29, 2012 · Viewed 13.1k times · Source

Let's take a simple "Account Registration" example, here is the flow:

  • User visit website
  • Click "Register" button and fill form, click "Save" button
  • MVC Controller: Validate UserName uniqueness by reading from ReadModel
  • RegisterCommand: Validate UserName uniqueness again (here is the question)

Of course, we can validate UserName uniqueness by reading from ReadModel in MVC controller to improve performance and user experience. However, we still need to validate the uniqueness again in RegisterCommand, and obviously, we should NOT access ReadModel in Commands.

If we do not use Event Sourcing, we can query the domain model, so that's no a problem. But if we're using Event Sourcing, we are not able to query domain model, so how can we validate UserName uniqueness in RegisterCommand?

Notice: User class has an Id property, and UserName is not the key property of User class. We can only get the domain object by Id when using event sourcing.

BTW: In the requirement, if the entered UserName is already taken, the website should show error message "Sorry, the user name XXX is not available" to the visitor. It's not acceptable to show a message, say, "We are creating your account, please wait, we will send the registration result to you via Email later", to the visitor.

Any ideas? Many thanks!

[UPDATE]

A more complex example:

Requirement:

When placing an order, the system should check the client's ordering history, if he is a valuable client (if the client placed at least 10 orders per month in the last year, he is valuable), we make 10% off to the order.

Implementation:

We create PlaceOrderCommand, and in the command, we need to query the ordering history to see if the client is valuable. But how can we do that? We shouldn't access ReadModel in command! As Mikael said, we can use compensating commands in the account registration example, but if we also use that in this ordering example, it would be too complex, and the code might be too difficult to maintain.

Answer

Mikael Östberg picture Mikael Östberg · Feb 29, 2012

If you validate the username using the read model before you send the command, we are talking about a race condition window of a couple of hundred milliseconds where a real race condition can happen, which in my system is not handled. It is just too unlikely to happen compared to the cost of dealing with it.

However, if you feel you must handle it for some reason or if you just feel you want to know how to master such a case, here is one way:

You shouldn't access the read model from the command handler nor the domain when using event sourcing. However, what you could do is to use a domain service that would listen to the UserRegistered event in which you access the read model again and check whether the username still isn't a duplicate. Of course you need to use the UserGuid here as well as your read model might have been updated with the user you just created. If there is a duplicate found, you have the chance of sending compensating commands such as changing the username and notifying the user that the username was taken.

That is one approach to the problem.

As you probably can see, it is not possible to do this in a synchronous request-response manner. To solve that, we are using SignalR to update the UI whenever there is something we want to push to the client (if they are still connected, that is). What we do is that we let the web client subscribe to events that contain information that is useful for the client to see immediately.

Update

For the more complex case: