Code snippets from 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 : Handles where T:Message {
private Handles next;
public TransactionalHandler(Handles 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(appliesEvent handler) {
lookup.add(typeof(T), handler);
}

public IEnumerable 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 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 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(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);
}



comments powered by Disqus