Skip to content

Commit 270b0c4

Browse files
authored
Merge pull request #10 from XerProjects/feature-remove-aggregateid
Remove generic AggregateRootId argument from types. Use Guid as ID.
2 parents 48551be + 415c844 commit 270b0c4

17 files changed

+201
-121
lines changed

Src/Xer.DomainDriven/AggregateRoot.cs

Lines changed: 58 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
namespace Xer.DomainDriven
66
{
7-
public abstract class AggregateRoot<TId> : Entity<TId>, IAggregateRoot<TId> where TId : IEquatable<TId>
7+
public abstract class AggregateRoot : Entity, IAggregateRoot
88
{
99
#region Declarations
1010

11-
private readonly Queue<IDomainEvent<TId>> _uncommittedDomainEvents = new Queue<IDomainEvent<TId>>();
11+
private readonly Queue<IDomainEvent> _uncommittedDomainEvents = new Queue<IDomainEvent>();
1212
private readonly DomainEventApplierRegistration _domainEventApplierRegistration = new DomainEventApplierRegistration();
1313

1414
#endregion Declarations
@@ -19,7 +19,7 @@ public abstract class AggregateRoot<TId> : Entity<TId>, IAggregateRoot<TId> wher
1919
/// Constructor.
2020
/// </summary>
2121
/// <param name="aggregateRootId">Id of aggregate root.</param>
22-
public AggregateRoot(TId aggregateRootId)
22+
public AggregateRoot(Guid aggregateRootId)
2323
: base(aggregateRootId)
2424
{
2525
}
@@ -30,7 +30,7 @@ public AggregateRoot(TId aggregateRootId)
3030
/// <param name="aggregateRootId">Id of aggregate root.</param>
3131
/// <param name="created">Created date.</param>
3232
/// <param name="updated">Updated date.</param>
33-
public AggregateRoot(TId aggregateRootId, DateTime created, DateTime updated)
33+
public AggregateRoot(Guid aggregateRootId, DateTime created, DateTime updated)
3434
: base(aggregateRootId, created, updated)
3535
{
3636
}
@@ -45,15 +45,15 @@ public AggregateRoot(TId aggregateRootId, DateTime created, DateTime updated)
4545
/// Get an event stream of all the uncommitted domain events applied to the aggregate.
4646
/// </summary>
4747
/// <returns>Stream of uncommitted domain events.</returns>
48-
IDomainEventStream<TId> IAggregateRoot<TId>.GetUncommitedDomainEvents()
48+
IDomainEventStream IAggregateRoot.GetDomainEventsMarkedForCommit()
4949
{
50-
return new DomainEventStream<TId>(Id, _uncommittedDomainEvents);
50+
return new DomainEventStream(Id, _uncommittedDomainEvents);
5151
}
5252

5353
// <summary>
5454
// Clear all internally tracked domain events.
5555
// </summary>
56-
void IAggregateRoot<TId>.ClearUncommitedDomainEvents()
56+
void IAggregateRoot.MarkDomainEventsAsCommitted()
5757
{
5858
_uncommittedDomainEvents.Clear();
5959
}
@@ -67,17 +67,17 @@ void IAggregateRoot<TId>.ClearUncommitedDomainEvents()
6767
/// </summary>
6868
/// <typeparam name="TDomainEvent">Domain event to be applied.</typeparam>
6969
/// <param name="domainEventApplier">Domain event applier.</param>
70-
protected void RegisterDomainEventApplier<TDomainEvent>(Action<TDomainEvent> domainEventApplier) where TDomainEvent : class, IDomainEvent<TId>
70+
protected void RegisterDomainEventApplier<TDomainEvent>(Action<TDomainEvent> domainEventApplier) where TDomainEvent : class, IDomainEvent
7171
{
7272
_domainEventApplierRegistration.RegisterApplierFor<TDomainEvent>(domainEventApplier);
7373
}
7474

7575
/// <summary>
76-
/// Apply domain event to this entity and mark domain event for commit.
76+
/// Apply domain event to this aggregate root and mark domain event for commit.
7777
/// </summary>
7878
/// <typeparam name="TDomainEvent">Type of domain event to apply.</typeparam>
7979
/// <param name="domainEvent">Instance of domain event to apply.</param>
80-
protected void ApplyDomainEvent<TDomainEvent>(TDomainEvent domainEvent) where TDomainEvent : IDomainEvent<TId>
80+
protected void ApplyDomainEvent<TDomainEvent>(TDomainEvent domainEvent) where TDomainEvent : IDomainEvent
8181
{
8282
if (domainEvent == null)
8383
{
@@ -88,6 +88,41 @@ protected void ApplyDomainEvent<TDomainEvent>(TDomainEvent domainEvent) where TD
8888
InvokeDomainEventApplier(domainEvent);
8989
}
9090

91+
/// <summary>
92+
/// Apply domain event to this aggregate root wihtout marking domain event for commit.
93+
/// </summary>
94+
/// <typeparam name="TDomainEvent">Type of domain event to replay.</typeparam>
95+
/// <param name="domainEvent">Instance of domain event to replay.</param>
96+
protected void ReplayDomainEvent<TDomainEvent>(TDomainEvent domainEvent) where TDomainEvent : IDomainEvent
97+
{
98+
if (domainEvent == null)
99+
{
100+
throw new ArgumentNullException(nameof(domainEvent));
101+
}
102+
103+
// Invoke and track the event to save to event store.
104+
InvokeDomainEventApplier(domainEvent, markDomainEventForCommit: false);
105+
}
106+
107+
/// <summary>
108+
/// Executes when a domain event is successfully applied.
109+
/// </summary>
110+
/// <param name="domainEvent">Successfully applied domain event.</param>
111+
protected virtual void OnDomainEventApplied(IDomainEvent domainEvent)
112+
{
113+
// Update timestamp.
114+
Updated = domainEvent.TimeStamp;
115+
}
116+
117+
/// <summary>
118+
/// Add domain event to list of tracked domain events.
119+
/// </summary>
120+
/// <param name="domainEvent">Domain event instance to track.</param>
121+
protected virtual void MarkAppliedDomainEventForCommit(IDomainEvent domainEvent)
122+
{
123+
_uncommittedDomainEvents.Enqueue(domainEvent);
124+
}
125+
91126
#endregion Protected Methods
92127

93128
#region Functions
@@ -98,22 +133,20 @@ protected void ApplyDomainEvent<TDomainEvent>(TDomainEvent domainEvent) where TD
98133
/// <typeparam name="TDomainEvent">Type of the domain event to handle.</typeparam>
99134
/// <param name="domainEvent">Domain event instance to handle.</param>
100135
/// <param name="markDomainEventForCommit">True, if domain event should be marked/tracked for commit. Otherwise, false - which means domain event should just be replayed.</param>
101-
private void InvokeDomainEventApplier<TDomainEvent>(TDomainEvent domainEvent, bool markDomainEventForCommit = true) where TDomainEvent : IDomainEvent<TId>
136+
private void InvokeDomainEventApplier<TDomainEvent>(TDomainEvent domainEvent, bool markDomainEventForCommit = true) where TDomainEvent : IDomainEvent
102137
{
103-
Action<IDomainEvent<TId>> domainEventApplier = _domainEventApplierRegistration.GetApplierFor(domainEvent);
104-
if (domainEventApplier == null)
138+
if (!_domainEventApplierRegistration.TryGetApplierFor(domainEvent, out Action<IDomainEvent> domainEventApplier))
105139
{
106-
throw new DomainEventNotAppliedException<TId>(domainEvent,
140+
throw new DomainEventNotAppliedException(domainEvent,
107141
$@"{GetType().Name} has no registered domain event applier to apply domain event of type {domainEvent.GetType().Name}.
108-
Register domain event appliers by calling {nameof(RegisterDomainEventApplier)} method during object construction.");
142+
Register domain event appliers by calling {nameof(RegisterDomainEventApplier)} method in constructor.");
109143
}
110144

111145
try
112146
{
113147
domainEventApplier.Invoke(domainEvent);
114148

115-
// Update timestamp.
116-
Updated = domainEvent.TimeStamp;
149+
OnDomainEventApplied(domainEvent);
117150

118151
if (markDomainEventForCommit)
119152
{
@@ -122,20 +155,11 @@ private void InvokeDomainEventApplier<TDomainEvent>(TDomainEvent domainEvent, bo
122155
}
123156
catch (Exception ex)
124157
{
125-
throw new DomainEventNotAppliedException<TId>(domainEvent,
158+
throw new DomainEventNotAppliedException(domainEvent,
126159
$"Exception occured while trying to apply domain event of type {domainEvent.GetType().Name}.",
127160
ex);
128161
}
129162
}
130-
131-
/// <summary>
132-
/// Add domain event to list of tracked domain events.
133-
/// </summary>
134-
/// <param name="domainEvent">Domain event instance to track.</param>
135-
private void MarkAppliedDomainEventForCommit(IDomainEvent<TId> domainEvent)
136-
{
137-
_uncommittedDomainEvents.Enqueue(domainEvent);
138-
}
139163

140164
#endregion Functions
141165

@@ -146,14 +170,14 @@ private void MarkAppliedDomainEventForCommit(IDomainEvent<TId> domainEvent)
146170
/// </summary>
147171
private class DomainEventApplierRegistration
148172
{
149-
private readonly IDictionary<Type, Action<IDomainEvent<TId>>> _applierByDomainEventType = new Dictionary<Type, Action<IDomainEvent<TId>>>();
173+
private readonly Dictionary<Type, Action<IDomainEvent>> _applierByDomainEventType = new Dictionary<Type, Action<IDomainEvent>>();
150174

151175
/// <summary>
152176
/// Register action to be executed for the domain event.
153177
/// </summary>
154178
/// <typeparam name="TDomainEvent">Type of domain event to apply.</typeparam>
155179
/// <param name="applier">Action to apply the domain event to the aggregate.</param>
156-
public void RegisterApplierFor<TDomainEvent>(Action<TDomainEvent> applier) where TDomainEvent : class, IDomainEvent<TId>
180+
public void RegisterApplierFor<TDomainEvent>(Action<TDomainEvent> applier) where TDomainEvent : class, IDomainEvent
157181
{
158182
if (applier == null)
159183
{
@@ -167,7 +191,7 @@ public void RegisterApplierFor<TDomainEvent>(Action<TDomainEvent> applier) where
167191
throw new InvalidOperationException($"A domain event applier that applies {domainEventType.Name} has already been registered.");
168192
}
169193

170-
Action<IDomainEvent<TId>> domainEventApplier = (d) =>
194+
Action<IDomainEvent> domainEventApplier = (d) =>
171195
{
172196
TDomainEvent domainEvent = d as TDomainEvent;
173197
if (domainEvent == null)
@@ -187,17 +211,16 @@ public void RegisterApplierFor<TDomainEvent>(Action<TDomainEvent> applier) where
187211
/// Get action to execute for the applied domain event.
188212
/// </summary>
189213
/// <param name="domainEvent">Domain event to apply.</param>
190-
/// <returns>Action that applies the domain event to the aggregate.</returns>
191-
public Action<IDomainEvent<TId>> GetApplierFor(IDomainEvent<TId> domainEvent)
214+
/// <param name="domainEventApplier">Action that applies the domain event to the aggregate.</param>
215+
/// <returns>True, if a registered domain event applier is found. Otherwise, false.</returns>
216+
public bool TryGetApplierFor(IDomainEvent domainEvent, out Action<IDomainEvent> domainEventApplier)
192217
{
193218
if (domainEvent == null)
194219
{
195220
throw new ArgumentNullException(nameof(domainEvent));
196221
}
197222

198-
_applierByDomainEventType.TryGetValue(domainEvent.GetType(), out Action<IDomainEvent<TId>> domainEventAction);
199-
200-
return domainEventAction;
223+
return _applierByDomainEventType.TryGetValue(domainEvent.GetType(), out domainEventApplier);
201224
}
202225
}
203226

Src/Xer.DomainDriven/DomainEventStream.cs

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@
55

66
namespace Xer.DomainDriven
77
{
8-
public class DomainEventStream<TAggregateRootId> : IDomainEventStream<TAggregateRootId>,
9-
IEnumerable<IDomainEvent<TAggregateRootId>>
10-
where TAggregateRootId : IEquatable<TAggregateRootId>
8+
public class DomainEventStream : IDomainEventStream, IEnumerable<IDomainEvent>
119
{
1210
#region Declarations
1311

14-
private readonly ICollection<IDomainEvent<TAggregateRootId>> _domainEvents;
12+
private readonly List<IDomainEvent> _domainEvents;
1513

1614
#endregion Declarations
1715

@@ -20,7 +18,7 @@ public class DomainEventStream<TAggregateRootId> : IDomainEventStream<TAggregate
2018
/// <summary>
2119
/// Id of the aggregate root which owns this stream.
2220
/// </summary>
23-
public TAggregateRootId AggregateRootId { get; }
21+
public Guid AggregateRootId { get; }
2422

2523
/// <summary>
2624
/// Get number of domain events in the stream.
@@ -35,18 +33,18 @@ public class DomainEventStream<TAggregateRootId> : IDomainEventStream<TAggregate
3533
/// Constructor to create an empty stream for the aggregate.
3634
/// </summary>
3735
/// <param name="aggreggateRootId">ID of the aggregate root.</param>
38-
public DomainEventStream(TAggregateRootId aggreggateRootId)
36+
public DomainEventStream(Guid aggreggateRootId)
3937
{
4038
AggregateRootId = aggreggateRootId;
41-
_domainEvents = new List<IDomainEvent<TAggregateRootId>>();
39+
_domainEvents = new List<IDomainEvent>();
4240
}
4341

4442
/// <summary>
4543
/// Constructs a new instance of a read-only stream.
4644
/// </summary>
4745
/// <param name="aggregateRootId">Id of the aggregate root which owns this stream.</param>
4846
/// <param name="domainEvents">Domain events.</param>
49-
public DomainEventStream(TAggregateRootId aggregateRootId, IEnumerable<IDomainEvent<TAggregateRootId>> domainEvents)
47+
public DomainEventStream(Guid aggregateRootId, IEnumerable<IDomainEvent> domainEvents)
5048
{
5149
if (domainEvents == null)
5250
{
@@ -66,7 +64,7 @@ public DomainEventStream(TAggregateRootId aggregateRootId, IEnumerable<IDomainEv
6664
/// </summary>
6765
/// <param name="domainEventToAppend">Domain event to append to the domain event stream.</param>
6866
/// <returns>New instance of domain event stream with the appended domain event.</returns>
69-
public DomainEventStream<TAggregateRootId> AppendDomainEvent(IDomainEvent<TAggregateRootId> domainEventToAppend)
67+
public DomainEventStream AppendDomainEvent(IDomainEvent domainEventToAppend)
7068
{
7169
if (domainEventToAppend == null)
7270
{
@@ -78,17 +76,17 @@ public DomainEventStream<TAggregateRootId> AppendDomainEvent(IDomainEvent<TAggre
7876
throw new InvalidOperationException("Cannot append domain event belonging to a different aggregate root.");
7977
}
8078

81-
return AppendDomainEventStream(new DomainEventStream<TAggregateRootId>(AggregateRootId, new[] { domainEventToAppend }));
79+
return new DomainEventStream(AggregateRootId, this.Concat(new[] { domainEventToAppend }));
8280
}
8381

8482
/// <summary>
8583
/// Creates a new domain event stream which has the appended domain event stream.
8684
/// </summary>
8785
/// <param name="streamToAppend">Domain event stream to append to this domain event stream.</param>
8886
/// <returns>New instance of domain event stream with the appended domain event stream.</returns>
89-
public DomainEventStream<TAggregateRootId> AppendDomainEventStream(IDomainEventStream<TAggregateRootId> streamToAppend)
87+
public DomainEventStream AppendDomainEventStream(IDomainEventStream streamToAppend)
9088
{
91-
if(streamToAppend == null)
89+
if (streamToAppend == null)
9290
{
9391
throw new ArgumentNullException(nameof(streamToAppend));
9492
}
@@ -98,16 +96,16 @@ public DomainEventStream<TAggregateRootId> AppendDomainEventStream(IDomainEventS
9896
throw new InvalidOperationException("Cannot append domain events belonging to a different aggregate root.");
9997
}
10098

101-
return new DomainEventStream<TAggregateRootId>(AggregateRootId, this.Concat(streamToAppend));
99+
return new DomainEventStream(AggregateRootId, this.Concat(streamToAppend));
102100
}
103101

104102
/// <summary>
105103
/// Get enumerator.
106104
/// </summary>
107105
/// <returns>Enumerator which yields domain events until iterated upon.</returns>
108-
public IEnumerator<IDomainEvent<TAggregateRootId>> GetEnumerator()
106+
public IEnumerator<IDomainEvent> GetEnumerator()
109107
{
110-
foreach(IDomainEvent<TAggregateRootId> domainEvent in _domainEvents)
108+
foreach (IDomainEvent domainEvent in _domainEvents)
111109
{
112110
yield return domainEvent;
113111
}
@@ -119,7 +117,7 @@ public IEnumerator<IDomainEvent<TAggregateRootId>> GetEnumerator()
119117
/// <returns>Enumerator which yields domain events until iterated upon.</returns>
120118
IEnumerator IEnumerable.GetEnumerator()
121119
{
122-
foreach (IDomainEvent<TAggregateRootId> domainEvent in _domainEvents)
120+
foreach (IDomainEvent domainEvent in _domainEvents)
123121
{
124122
yield return domainEvent;
125123
}

Src/Xer.DomainDriven/Entity.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
namespace Xer.DomainDriven
44
{
5-
public abstract class Entity<TId> : IEntity<TId> where TId : IEquatable<TId>
5+
public abstract class Entity : IEntity
66
{
77
/// <summary>
88
/// Unique ID.
99
/// </summary>
10-
public TId Id { get; protected set; }
10+
public Guid Id { get; protected set; }
1111

1212
/// <summary>
1313
/// Date when entitity was created.
@@ -26,7 +26,7 @@ public abstract class Entity<TId> : IEntity<TId> where TId : IEquatable<TId>
2626
/// This will set <see cref="Entity.Created"/> and <see cref="Entity.Updated"/> properties to <see cref="DateTime.UtcNow"/>.
2727
/// </remarks>
2828
/// <param name="entityId">ID of entity.</param>
29-
public Entity(TId entityId)
29+
public Entity(Guid entityId)
3030
{
3131
Id = entityId;
3232
Created = DateTime.UtcNow;
@@ -39,7 +39,7 @@ public Entity(TId entityId)
3939
/// <param name="entityId">ID of entity.</param>
4040
/// <param name="created">Created date.</param>
4141
/// <param name="updated">Updated date.</param>
42-
public Entity(TId entityId, DateTime created, DateTime updated)
42+
public Entity(Guid entityId, DateTime created, DateTime updated)
4343
{
4444
Id = entityId;
4545
Created = created;

Src/Xer.DomainDriven/Exceptions/DomainEventNotAppliedException.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,22 @@
22

33
namespace Xer.DomainDriven.Exceptions
44
{
5-
public class DomainEventNotAppliedException<TAggregateRootId> : Exception where TAggregateRootId : IEquatable<TAggregateRootId>
5+
public class DomainEventNotAppliedException : Exception
66
{
7-
public TAggregateRootId AggregateRootId { get; }
8-
public IDomainEvent<TAggregateRootId> DomainEvent { get; }
7+
public Guid AggregateRootId { get; }
8+
public IDomainEvent DomainEvent { get; }
99

10-
public DomainEventNotAppliedException(IDomainEvent<TAggregateRootId> domainEvent)
10+
public DomainEventNotAppliedException(IDomainEvent domainEvent)
1111
: this(domainEvent, string.Empty)
1212
{
1313
}
1414

15-
public DomainEventNotAppliedException(IDomainEvent<TAggregateRootId> domainEvent, string message)
15+
public DomainEventNotAppliedException(IDomainEvent domainEvent, string message)
1616
: this(domainEvent, message, null)
1717
{
1818
}
1919

20-
public DomainEventNotAppliedException(IDomainEvent<TAggregateRootId> domainEvent, string message, Exception innerException)
20+
public DomainEventNotAppliedException(IDomainEvent domainEvent, string message, Exception innerException)
2121
: base(message, innerException)
2222
{
2323
AggregateRootId = domainEvent.AggregateRootId;

0 commit comments

Comments
 (0)