private async Task CommitChanges(AggregateRoot <TAggregateKey, TEventKey> aggregate) { var expectedVersion = aggregate.LastCommittedVersion; var item = await _eventStorageProvider.GetLastEventAsync(aggregate.Id); if ((item != null) && (expectedVersion == (int)StreamState.NoStream)) { throw new AggregateCreationException($"Aggregate {item.CorrelationId} can't be created as it already exists with version {item.TargetVersion + 1}"); } else if ((item != null) && ((item.TargetVersion + 1) != expectedVersion)) { throw new ConcurrencyException($"Aggregate {item.CorrelationId} has been modified externally and has an updated state. Can't commit changes."); } var changesToCommit = aggregate .GetUncommittedChanges() .Select(e => (IEvent <TEventKey, TAggregate, TAggregateKey>)e) .ToList(); //perform pre commit actions foreach (var e in changesToCommit) { DoPreCommitTasks(e); } //CommitAsync events to storage provider await _eventStorageProvider.SaveAsync(aggregate); //Publish to event publisher asynchronously foreach (var e in changesToCommit) { if (_eventPublisher != null) { await _eventPublisher.PublishAsync(e); } } //If the Aggregate implements snapshottable if ((aggregate is ISnapshottable <TSnapshotKey, TAggregateKey, TSnapshot> snapshottable) && (_snapshotStorageProvider != null)) { //Every N events we save a snapshot if ((aggregate.CurrentVersion >= _snapshotStorageProvider.SnapshotFrequency) && ( (changesToCommit.Count >= _snapshotStorageProvider.SnapshotFrequency) || (aggregate.CurrentVersion % _snapshotStorageProvider.SnapshotFrequency < changesToCommit.Count) || (aggregate.CurrentVersion % _snapshotStorageProvider.SnapshotFrequency == 0) ) ) { var snapshot = snapshottable.TakeSnapshot(); await _snapshotStorageProvider.SaveSnapshotAsync(snapshot); } } aggregate.MarkChangesAsCommitted(); }
private async Task CommitChangesAsync(Aggregate aggregate) { var expectedVersion = aggregate.LastCommittedVersion; var item = await _eventStorageProvider.GetLastEventAsync(aggregate.GetType(), aggregate.Id) .ConfigureAwait(false); if (item != null && expectedVersion == (int)Aggregate.StreamState.NoStream) { throw new AggregateCreationException(aggregate.Id, item.TargetVersion + 1); } if (item != null && item.TargetVersion + 1 != expectedVersion) { throw new ConcurrencyException(aggregate.Id); } var changesToCommit = aggregate.GetUncommittedChanges().ToList(); Logger.Debug("Performing pre commit checks"); //perform pre commit actions foreach (var e in changesToCommit) { DoPreCommitTasks(e); } //CommitAsync events to storage provider await _eventStorageProvider.CommitChangesAsync(aggregate) .ConfigureAwait(false); //Publish to event publisher asynchronously if (_eventPublisher != null) { foreach (var e in changesToCommit) { await _eventPublisher.PublishAsync(e) .ConfigureAwait(false); } } //If the Aggregate implements snapshottable var snapshottable = aggregate as ISnapshottable; if (snapshottable != null && _snapshotStorageProvider != null) { //Every N events we save a snapshot if (ShouldCreateSnapShot(aggregate, changesToCommit)) { await _snapshotStorageProvider.SaveSnapshotAsync(aggregate.GetType(), snapshottable.TakeSnapshot()) .ConfigureAwait(false); } } aggregate.MarkChangesAsCommitted(); }
public async Task GetLastEventAsync_should_return_last_event() { var aggregateId = Guid.NewGuid(); var aggregate = new BankAccount(aggregateId, "Account Name"); await CommitChangesAsync(aggregate) .ConfigureAwait(false); var actual = await _provider.GetLastEventAsync(aggregate.GetType(), aggregateId) .ConfigureAwait(false); actual.AggregateId.Should().Be(aggregateId); actual.TargetVersion.Should().Be(-1); actual.Should().BeOfType <AccountCreatedEvent>(); }
private async Task CommitChanges(TAggregate aggregate) { var expectedVersion = aggregate.LastCommittedVersion; var item = await _eventStorageProvider.GetLastEventAsync <TAggregate, TAggregateKey>(aggregate.Id); if ((item != null)) { if (expectedVersion == (long)StreamState.NoStream) { throw new AggregateCreationException($"Aggregate {item.CorrelationId} can't be created as it already exists with version {item.TargetVersion + 1}"); } if ((item.TargetVersion + 1) != expectedVersion) { throw new ConcurrencyException($"Aggregate {item.CorrelationId} has been modified externally and has an updated state. Can't commit changes."); } } var changesToCommit = aggregate .GetUncommittedChanges() .Cast <IEvent <TAggregate, TAggregateKey, TEventKey> >() .ToList(); //perform pre commit actions DoPreCommitTasks(changesToCommit); //CommitAsync events to storage provider await _eventStorageProvider.SaveAsync <TAggregate, TAggregateKey>(aggregate.Id, changesToCommit); //Publish to event publisher asynchronously await PublishEventsAsync(changesToCommit); //If the Aggregate implements snapshottable await SaveSnapshotAsync(aggregate, changesToCommit); //Finally mark them committed aggregate.MarkChangesAsCommitted(); }
public Task <IEvent> GetLastEventAsync(Type aggregateType, Guid aggregateId) { return(LogMethodCallAsync(() => _decorated.GetLastEventAsync(aggregateType, aggregateId), new object[] { aggregateType, aggregateId })); }