-
Notifications
You must be signed in to change notification settings - Fork 536
/
Copy pathDomain.cs
153 lines (125 loc) · 4.49 KB
/
Domain.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
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");
if (AvailableQty - count < 0) throw new InvalidOperationException("Cannot remove a count greater than the available quantity");
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 MaxQtyChanged(_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;
}
}
}