예제 #1
0
 public Task <Event> GetLastEventAsync(Guid aggregateId) => storage.GetLastEventAsync(aggregateId);
예제 #2
0
        public async Task CommitAsync()
        {
            try
            {
                foreach (var aggregate in trackedAggregates.Values)
                {
                    if (!aggregate.HasEventSourcing())
                    {
                        throw new AggregateFeatureNotFoundException($"Aggregate '{aggregate.GetType().Name}:{aggregate.Id}' must has '{nameof(EventSourcingAggregateFeature)}' to uses '{nameof(EventSourcingRepository<TAggregate>)}'.");
                    }
                    var expectedVersion = aggregate.GetLastCommittedVersion();
                    var lastEvent       = await eventStorage.GetLastEventAsync(aggregate.Id);

                    if ((lastEvent != null) && (expectedVersion == 0))
                    {
                        throw new AggregateCreationException($"Aggregate '{aggregate.Id}' can't be created as it already exists with version {lastEvent.EventSourcing().TargetVersion + 1}");
                    }
                    else if ((lastEvent != null) && ((lastEvent.EventSourcing().TargetVersion + 1) != expectedVersion))
                    {
                        throw new ConcurrencyException($"Aggregate '{aggregate.Id}' has been modified externally and has an updated state. Can't commit changes.");
                    }
                    var changesToCommit = aggregate.GetPendingEvents();

                    //perform pre commit actions
                    foreach (var e in changesToCommit)
                    {
                        e.EventSourcing().EventCommittedTimestamp = DateTime.UtcNow;
                    }

                    //CommitAsync events to storage provider
                    await eventStorage.CommitAsync(aggregate.Id, changesToCommit);

                    aggregate.EventSourcing().LastCommittedVersion = aggregate.GetCurrentVersion();

                    // If the Aggregate is snapshottable
                    if (aggregate.IsSnapshottable())
                    {
                        if (aggregate.GetCurrentVersion() - aggregate.GetSnapshotVersion() > aggregate.GetSnapshotFrequency())
                        {
                            await snapshotStorage.SaveSnapshotAsync(aggregate.GetSnapshot());

                            aggregate.EventSourcing().SnapshotVersion = aggregate.GetCurrentVersion();
                        }
                    }

                    // Dispatch events asynchronously
                    foreach (var e in changesToCommit)
                    {
                        await eventDispatcher.DispatchAsync(e);
                    }

                    aggregate.ClearPendingEvents();
                }
                trackedAggregates.Clear();
            }
            catch (Exception ex)
            {
                log.Error($"Error '{ex.GetType().Name}' in '{nameof(EventSourcingRepository<TAggregate>)}.{nameof(CommitAsync)}': {ex.Message}", ex);
                throw;
            }
        }