forked from gregoryyoung/m-r
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDomain.cs
127 lines (103 loc) · 3.45 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
using System;
using System.Collections.Generic;
namespace SimpleCQRS
{
public class InventoryItem : AggregateRoot
{
private bool _activated;
private Guid _id;
private void Apply(InventoryItemCreated e)
{
_id = e.Id;
_activated = true;
}
private void Apply(InventoryItemDeactivated e)
{
_activated = false;
}
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");
ApplyChange(new ItemsCheckedInToInventory(_id, count));
}
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));
}
}
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;
}
}
}