Skip to content

Instantly share code, notes, and snippets.

@jasonmitchell
Created April 1, 2017 22:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jasonmitchell/2edadbce2208e14dee1227a5ab3a1c6f to your computer and use it in GitHub Desktop.
Save jasonmitchell/2edadbce2208e14dee1227a5ab3a1c6f to your computer and use it in GitHub Desktop.
Event Sourced Aggregates
using System;
using System.Collections.Generic;
namespace Aggregates
{
public abstract class Aggregate : IAggregate
{
private readonly Dictionary<Type, Action<object>> handlers = new Dictionary<Type, Action<object>>();
private readonly Queue<object> uncommittedEvents = new Queue<object>();
private int version;
public Guid Id { get; protected set; }
int IAggregate.Version => version;
IEnumerable<object> IAggregate.UncommittedEvents => uncommittedEvents;
IEnumerable<Type> IAggregate.EventTypes => handlers.Keys;
protected void Given<TEvent>(Action<TEvent> handler)
{
handlers.Add(typeof(TEvent), x => handler((TEvent)x));
}
protected void Then<TEvent>(TEvent e)
{
((IAggregate)this).Apply(e);
uncommittedEvents.Enqueue(e);
}
void IAggregate.Apply(object e)
{
handlers[e.GetType()](e);
version++;
}
void IAggregate.ClearEvents()
{
uncommittedEvents.Clear();
}
}
}
using System;
using System.Collections.Generic;
namespace Aggregates
{
public interface IAggregate
{
Guid Id { get; }
int Version { get; }
IEnumerable<object> UncommittedEvents { get; }
IEnumerable<Type> EventTypes { get; }
void Apply(object e);
void ClearEvents();
}
}
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace Aggregates.Sales
{
public class Order : Aggregate
{
private ReadOnlyCollection<OrderItem> items;
private bool paid;
private bool delivered;
private decimal TotalValue => items.Sum(x => x.Price);
private Order()
{
Given<OrderPlaced>(e =>
{
Id = e.Id;
items = new ReadOnlyCollection<OrderItem>(e.Items.Select(x => new OrderItem(x.ProductId, x.Price)).ToList());
});
Given<PaymentReceived>(e => paid = true);
Given<OrderDelivered>(e => delivered = true);
}
public Order(Guid id, List<OrderItem> items) : this()
{
Then(new OrderPlaced(id, items.Select(x => new OrderPlaced.Item(x.ProductId, x.Price)).ToList()));
}
public void Pay()
{
Then(new PaymentReceived(Id, TotalValue));
}
public void DeliveredToRecipient()
{
Then(new OrderDelivered(Id));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment