11

CQRS makes alot of sense. However it seems mutually exclusive to the approach of using an ORM that provides change tracking. If I have one "channel" for queries to get my objects as RO, then theres no changes to track. If I have another channel for CUD+ commands, its more of an RPC aproach with light DTOs, then sending self-tracking entities to be merged at a lower tier.

How can these two approaches (CQRS / ORM + STEs) be reconciled?

Josh Reuben
  • 577
  • 3
  • 20

2 Answers2

8

A common way to structure a CQRS application is to act upon the domain model within command handlers.

You would send a command DTO, and in the handler you would invoke methods on your domain objects (you would not set the properties of your domain entities, as this is a major anti-pattern).

The methods in your domain objects would be responsible for modifying the internal state of your domain.

And at that point, your ORM would be responsible for persisting the changes to the internal state of your domain objects.

This way of structuring a CQRS application does not utilize Event Sourcing, but does utilize an ORM and self-tracking entities.

Here's a very simplified example.

public class AccountController 
{
  [HttpPost]
  public ActionResult ChangePreferredStatus(Guid accountId, bool isPreferred)
  {
    if (isPreferred) {
      // in response to user action, our controller commands our application to carry out an operation/state transition
      Bus.SendCommand(new MakeAccountPreferredCommand(accountId));
    }
  }
}

public class MakeAccountPreferredCommandHander : IHandle<MakeAccountPreferredCommand>
{
  public void Handle(MakeAccountPreferredCommand command) 
  {
    using (var uow = new UnitOfWork()) {
      var account = accountRepository.Get(command.AccountId);
      if (account != null) {
        // we tell the domain what we want it to do, we DO NOT fiddle with its state
        account.MakePreferred();
      }
      uow.Accept(); // accepting the uow saves any changes to self-tracked entities
    }
  }
}

public class Account : SelfTrackedEntity
{
  private Guid accountId;
  private bool isPreferred; // ORM tracked *private* state

  public void MakePreferred() 
  {
    // entities are responsible for their own state and changing it
    ValidateForMakePreferred();
    isPreferred = true;
    RaiseEvent(new AccountMadePreferredEvent(accountId));
  }
}
quentin-starin
  • 26,121
  • 7
  • 68
  • 86
  • 1
    That makes no sense: If you are sending a command DTO, then you are not sending a STE. The concept of Self-Tracking Entities - query would read an object graph branch via service interface over an ORM. the client would make changes to the object graph branch and send it back to the ORM to merge tracked changes. I ask again, how can this be compatible with CQRS? – Josh Reuben Apr 10 '11 at 04:10
  • 1
    I added a code sample. You wouldn't send the ste's all the way to the client, no. That wouldn't be CQRS. But you can use self-tracked entities as I show to handle the command. With CQRS you usually make the commands and events light DTO's, and you implement *behavior* in the entities (rather than expose state). The objects you query would **not** be self-tracked entities. That's the *separation of command and query*. You *could* use the ORM for query, but that often implies unnecessarily lower performance unless you can turn off features like self tracking etc. – quentin-starin Apr 10 '11 at 05:48
  • so you are saying that STEs down to the ViewModel and CQRS are incompatable. I dont think they are incompatable, but I do think there would be wasteful duplication of infrastructure as you pass STEs up another channel to a very similar EDMX and attach and merge them in. – Josh Reuben Apr 10 '11 at 13:23
  • 2
    If you pass STEs down to the view, have them filled in there, then pass them back to a context to get saved that is most definitely **not CQRS**. Period. Your command side and query side are not separated in that scenario. – quentin-starin Apr 10 '11 at 16:15
  • How is it not CQRS if I use 2 seperate services: 1) one for querying entities from ORM A and 2) one for calling commands and passing STEs as params to ORM 2 for merging? – Josh Reuben Apr 12 '11 at 05:03
  • 1
    If you have an entity, for which inputs are displayed 1-to-1 for properties and those are filled in by a user, and you send the entity back up to have the changes picked up and fields updated in the DB, then what is your command? What is its name and how is that represented with a code artifact? – quentin-starin Apr 12 '11 at 17:36
  • 2
    It may be conceivable to twist such a scheme under the barest definition of CQRS, but that sort of architecture is practically the antithesis of CQRS. In a CQRS based architecture we **tell** our entities to do something (i.e., call a method), we don't fill them with individual bits of data. That is a gross violation of encapsulation. Also, I have trouble seeing how you would explicitly model a command with filled-in STE's, and explicitly modeling commands (and events) is a core principle of a CQRS based architecture. – quentin-starin Apr 12 '11 at 17:39
4

Do these approaches need to be reconciled?

If you're using CQRS, why would you need or want change tracking? It's not like your objects are doing round trips.

In my current client's implementation, we have MongoDB with NoRM on the Command side and SQL Server 2008 R2 with WCF Data Services on the query side. No need for Entity Framework on the command side, no need for entity tracking, ... and it works beautifully!

Roy Dictus
  • 32,551
  • 8
  • 60
  • 76