Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
using System;
using System.Collections.Generic;
namespace SimpleCQRS
{
public class InventoryItem : AggregateRoot
{
private bool _activated;
private Guid _id;
public int AvailableQty { get; set; }
public int MaxQty { get; set; } = 5;
private void Apply(InventoryItemCreated e)
{
_id = e.Id;
_activated = true;
}
private void Apply(InventoryItemDeactivated e)
{
_activated = false;
}
private void Apply(MaxQtyChanged e)
{
MaxQty = e.NewMaxQty;
}
private void Apply(ItemsCheckedInToInventory e)
{
AvailableQty += e.Count;
}
private void Apply(ItemsRemovedFromInventory e)
{
AvailableQty -= e.Count;
}
public void ChangeName(string newName)
{
if (string.IsNullOrEmpty(newName)) throw new ArgumentException("newName");
ApplyChange(new InventoryItemRenamed(_id, newName));
}
public void Remove(int count)
{
if (count <= 0) throw new InvalidOperationException("cant remove negative count from inventory");
ApplyChange(new ItemsRemovedFromInventory(_id, count));
}
public void CheckIn(int count)
{
if(count <= 0) throw new InvalidOperationException("must have a count greater than 0 to add to inventory");
if(AvailableQty + count > MaxQty) throw new InvalidOperationException("Checked in count will exceed Max Qty");
ApplyChange(new ItemsCheckedInToInventory(_id, count));
}
public void ChangeMaxQty(int newMaxQty)
{
if (newMaxQty <= 0) throw new InvalidOperationException("New Max Qty must be larger than 0");
if (newMaxQty < AvailableQty) throw new InvalidOperationException("New Max Qty cannot be less than Available Qty");
ApplyChange(new ItemsCheckedInToInventory(_id, newMaxQty));
}
public void Deactivate()
{
if(!_activated) throw new InvalidOperationException("already deactivated");
ApplyChange(new InventoryItemDeactivated(_id));
}
public override Guid Id
{
get { return _id; }
}
public InventoryItem()
{
// used to create in repository ... many ways to avoid this, eg making private constructor
}
public InventoryItem(Guid id, string name)
{
ApplyChange(new InventoryItemCreated(id, name, MaxQty));
}
}
public abstract class AggregateRoot
{
private readonly List<Event> _changes = new List<Event>();
public abstract Guid Id { get; }
public int Version { get; internal set; }
public IEnumerable<Event> GetUncommittedChanges()
{
return _changes;
}
public void MarkChangesAsCommitted()
{
_changes.Clear();
}
public void LoadsFromHistory(IEnumerable<Event> history)
{
foreach (var e in history) ApplyChange(e, false);
}
protected void ApplyChange(Event @event)
{
ApplyChange(@event, true);
}
// push atomic aggregate changes to local history for further processing (EventStore.SaveEvents)
private void ApplyChange(Event @event, bool isNew)
{
this.AsDynamic().Apply(@event);
if(isNew) _changes.Add(@event);
}
}
public interface IRepository<T> where T : AggregateRoot, new()
{
void Save(AggregateRoot aggregate, int expectedVersion);
T GetById(Guid id);
}
public class Repository<T> : IRepository<T> where T: AggregateRoot, new() //shortcut you can do as you see fit with new()
{
private readonly IEventStore _storage;
public Repository(IEventStore storage)
{
_storage = storage;
}
public void Save(AggregateRoot aggregate, int expectedVersion)
{
_storage.SaveEvents(aggregate.Id, aggregate.GetUncommittedChanges(), expectedVersion);
}
public T GetById(Guid id)
{
var obj = new T();//lots of ways to do this
var e = _storage.GetEventsForAggregate(id);
obj.LoadsFromHistory(e);
return obj;
}
}
}