Code snippets from Video: GregYoung 8 CQRS Class

public class DeactivateInventoryItemCommand {
public readonly Guid InventoryItemId;
public readonly string Comment;


public DeactivateInventoryItemCommand (Guid id, string comment) {
InventoryItemId = id;
Comment = comment;
}
void DeactivateInventoryItem(Guid, string comment)

CommandHandler contains no logic, logic is in domain object delegates to domain object

public class DeactivateInventoryItemHandler : Handles<DeactivateInventoryItem> {
public DeactivateInventoryItemHandler(InventoryItemRepository rep){}

void Handle(DeactivateInventoryItem cmd) {
var item = repository.GetById(cmd.Id);
item.Deactivate(cmd.Comment);
}
}

Application Services cross-cutting concerns (logging, authentication)

public class TransactionalHandler<T> : Handles<T> where T:Message {
private Handles<T> next;
public TransactionalHandler(Handles<T> Next) {
next = Next;
}


public Handle(T cmd) {
using(new UnitOfWork()) {
next.Handle(cmd);
}
}
}

public class LoggingHandler<T> : Handles<T> where T:Message {
private Handles<T> next;
public TransactionalHandler(Handles<T> Next) {
next = Next;
}



public Handle(T cmd) {
using(new UnitOfWork()) {
next.Handle(cmd);
}
}
}
var handler = new TransactionalHandler<DeactiveateInventoryItemCommand>(
new LoggingHandler<DeactiveateInventoryItemCommand>(
new DeactiveateInventoryItemHandler()))

CommandHandler only 1

[RequiresPermission("Admin")]
[Transactional]
[LogsTo("C:\\foo.txt")]
public class DeactivateInventoryItemHandler : Handles<DeactivateInventoryItem> {
public DeactivateInventoryItemHandler(InventoryItemRepository rep){}


void Handle(DeactivateInventoryItem cmd) {
var item = repository.GetById(cmd.Id);
item.Deactivate(cmd.Comment);
}
}

command and event

public class DeactivateInventoryItem {
public readonly Guid InventoryItemId;
public readonly string Comment;



public DeactivateInventoryItemCommand (Guid id, string comment) {
InventoryItemId = id;
Comment = comment;
}

public class InventoryItemDeactivated {
public readonly Guid InventoryItemId;
public readonly string Comment;


public InventoryItemDeactivated (Guid id, string comment) {
InventoryItemId = id;
Comment = comment;
}

EventHandler

[Transactional]
public class DeactivatedEventHandler : Handles <InventoryItemDeactivatedEvent> {
public void Handle(InventoryItemDeactivatedEvent e) {
INSERT INTO FOO () VALUES e.cjjd e.ccc
}
}

AggregateRoot

public class InventoryItem : AggregateRoot {
WarehouseLocationInformation info;
bool activated;


public InventoryItem() {
RegisterHandler(typeof(DeactivatedEvent), ApplyDeactivatedEvent);
RegisterHandler(typeof(WarehouseLocationInformationRegistered), ApplyWareh...Registered);
}


private void Apply(DeactivatedEvent e) {
activated = false;
}

private void Apply(WarehouseLocationInformationRegistered e) {
info = new WarehouseLocationInformation(e.PhysicalLocation, e.GeoLocation, e.PaymentRate);
}


private void Deactivate() {
if(!activated) throw new InvalidOperationException();
if(comment==null) throw ...();
ApplyEvent(new InventoryDeactivatedEvent(id));
}
}
public class AggregateRoot : IAggregateRoot {
private Dictionary<Type, appliesEvent> lookup = new Dictionary<Type, appliesEvent>();


protected void RegisterHandler<T>(appliesEvent handler) {
lookup.add(typeof(T), handler);
}


public IEnumerable<Event> GetChanges() {
foreach(Event e in events) yield return e;
events.Clear();
}


protected void ApplyEvent(Event e) { ApplyEvent(e, true); }


private void ApplyEvent(Event e, bool add) {
appliesEvent handler;
if(!lookup.TryGetValue(e.getType(), out handler)) {
throw new HandlerNotFoundException();
}
handler(e);
if(add) UnitOfWork.GetCurrent().Enregister(e);
}


public void LoadFromHistory(IEnumerable<Event> events) {
foreach(Event e in events) {
ApplyEvent(e, false);
}
}
}

InventoryItemDeactivatedEvent

public class InventoryItemDeactivatedEvent : Event {
public readonly Guid Id;
public InventoryItemDeactivatedEvent (Guid id) {
Id = id;
}

Test

[TestFixture]
public class when_an_inventory_item_is_deactivated : AggregateRootTestFixture<InventoryItem> {
private Guid id = Guid.newGuid();


protected override IEnumerable<Event> Given() {
yield return New.InventoryItemCreated.WithName("Test");
}


protected override void When() {
sut.Deactivate();
}


[Test]
public void should_publish_deactivated_Event() {
Assert.Inconclusive();
}


[Test]
public void should_publish_event_with_correct_id() {
Assert.AreEquel(id, ((InventoryDeactivatedEvent) events[0]).AggregateId);
}
}
public abstract class AggregateRootTestFixture<T> : where T:IAggregateRoot, new() {
protected IAggregateRoot root;
protected Exception caught = null;
protected T sut;
protected List<Event> events;

protected abstract IEnumerable<Event> Given();
protected abstract void When();


[SetUp]
public void Setup() {
root = new T();
root.LoadFromHistory(Given());
try{
When();
events = new List<Event>(root.GetChanges());
} catch(Exception Ex) {
caught = Ex;
}
}
}

bdd

Given a set of events
when I issue a command
expect a set of events
Given
an inventory item created
When I
deactivate inventory item
expect
inventory item deactivated
Given
an inventory item created
an inventory item deactivated
When I
deactivate inventory item
expect
invalidoperation exception

View

public class InventoryCountView : Handles<InventoryAddedEvent>, Handles<InventoryItemRemovedEvent>, Handles<InventoryItemCreatedEvent>
public void Handle(InventoryItemAddedEvent) {
update InventoryCountView set currentcount = currentcount + e.Count
}


public void Handle(InventoryItemCreatedEvent e) {
insert into InventoryCountView currentcount values 0
}

Versioning

public class InventoryItemDeactivatedEvent : Event {
public readonly Guid Id;
public InventoryItemDeactivatedEvent (Guid id) {
Id = id;
}
}

public class InventoryItemDeactivatedEvent_v2 : Event {
public readonly Guid Id;
public readonly string Comment;
public InventoryItemDeactivatedEvent (Guid id, string comment) {
Id = id;
Comment = commment;
}
}

public class InventoryItemDeactivatedEvent_v3 : Event {
T ConvertTo<T,V>(V v) where T:Message, V:Message


DeactivatedEvent_v2 ConvertTo(DeactivatedEvent v) {
return new DeactivatedEvent_v2(v.Id, null);
}