title: How to handle concurrent constraints across aggregate roots
body: <p>I'm afraid I already know the answer, but I'm hoping that somebody can provide an alternative solution that haven't found before. As always doing DDD according to <a href="http://dddcommunity.org/library/vernon_2011" rel="noreferrer">Effective Aggregate Design</a> is more difficult than I thought, but here's my scenario. </p>
  
  <ul>
  <li>We have two ARs, User and RoleGroup</li>
  <li>A User can be granted a particular RoleGroup and thereby obtains the permissions provided by the Roles (a collection value object) in that role group. The identity of the role group is kept in the User AR as another VA. </li>
  <li>When a RoleGroup is removed from the system, we raise a domain event that a handler uses to find all users referring to that RoleGroup and to remove the reference. The corresponding projection denormalizer will use that same event to update the effective roles of the User. This is a combination of the individual roles granted to that User and the roles of all granted RoleGroups.</li>
  <li>This doesn't have to be transactional (iow it can be eventually consistent).</li>
  <li>We use Event Sourcing using Jonathan Oliver's EventStore 3.0 and elements from Lokad.CQRS and NCQRS.</li>
  </ul>
  
  <p>So, in theory, when one request (it's an ASP.NET MVC app) is executing the scenario mentioned above, it is possible that another request is granting that same RoleGroup to a User. If that happens just after the above mentioned domain event handler scans for users related to that RoleGroup, that request will complete. At that point you have a RoleGroup that is deleted (albeit not physically) and a User that is still holding the identity of that RoleGroup. </p>
  
  <p>How do you prevent this? We're currently looking at making the identity of the Users granted a particular RoleGroup part of that RoleGroup AR, so that deleting a RoleGroup and granting it to a user will cause a optimistic concurrency conflict. But somehow, this doesn't feel like the correct solution. </p>