Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is CQRS compatible with Entity Framework Self Tracking Enities / WCF RIA Services?

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?

like image 200
Josh Reuben Avatar asked Apr 08 '11 18:04

Josh Reuben


2 Answers

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));
  }
}
like image 95
quentin-starin Avatar answered Oct 21 '22 15:10

quentin-starin


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!

like image 42
Roy Dictus Avatar answered Oct 21 '22 15:10

Roy Dictus