44
55namespace 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
0 commit comments