protected override async Task <ReadModelUpdateResult <TReadModel> > UpdateAsync(
            IReadModelContext readModelContext,
            IReadOnlyCollection <IDomainEvent> domainEvents,
            ReadModelEnvelope <TReadModel> readModelEnvelope,
            CancellationToken cancellationToken)
        {
            var readModel = readModelEnvelope.ReadModel;

            if (readModel == null)
            {
                readModel = await ReadModelFactory.CreateAsync(
                    readModelEnvelope.ReadModelId,
                    cancellationToken)
                            .ConfigureAwait(false);
            }

            await ReadModelDomainEventApplier.UpdateReadModelAsync(
                readModel,
                domainEvents,
                readModelContext,
                cancellationToken)
            .ConfigureAwait(false);

            return(readModelEnvelope.AsModifedResult(
                       readModel,
                       readModelEnvelope.Version.GetValueOrDefault() + 1 // the best we can do
                       ));
        }
示例#2
0
 private async Task <TReadModel> GetOrCreateReadModel(ReadModelEnvelope <TReadModel> readModelEnvelope,
                                                      CancellationToken cancellationToken)
 {
     return(readModelEnvelope.ReadModel
            ?? await ReadModelFactory
            .CreateAsync(readModelEnvelope.ReadModelId, cancellationToken)
            .ConfigureAwait(false));
 }
示例#3
0
        protected override async Task <ReadModelEnvelope <TReadModel> > UpdateAsync(
            IReadModelContext readModelContext,
            IReadOnlyCollection <IDomainEvent> domainEvents,
            ReadModelEnvelope <TReadModel> readModelEnvelope,
            CancellationToken cancellationToken)
        {
            var readModel = readModelEnvelope.ReadModel ?? new TReadModel();
            await ReadModelDomainEventApplier.UpdateReadModelAsync(readModel, domainEvents, readModelContext, cancellationToken).ConfigureAwait(false);

            return(ReadModelEnvelope <TReadModel> .With(readModel));
        }
        protected override async Task <ReadModelUpdateResult <TReadModel> > UpdateAsync(
            IReadModelContext readModelContext,
            IReadOnlyCollection <IDomainEvent> domainEvents,
            ReadModelEnvelope <TReadModel> readModelEnvelope,
            CancellationToken cancellationToken)
        {
            if (!domainEvents.Any())
            {
                throw new ArgumentException("No domain events");
            }

            var expectedVersion = domainEvents.Min(d => d.AggregateSequenceNumber) - 1;
            var envelopeVersion = readModelEnvelope.Version;

            IReadOnlyCollection <IDomainEvent> eventsToApply;

            if (envelopeVersion.HasValue && expectedVersion != envelopeVersion)
            {
                var version = envelopeVersion.Value;
                if (expectedVersion < version)
                {
                    Log.Verbose(() =>
                                $"Read model '{typeof(TReadModel)}' with ID '{readModelEnvelope.ReadModelId}' already has version {version} compared to {expectedVersion}, skipping");

                    return(readModelEnvelope.AsUnmodifedResult());
                }

                // Apply missing events
                TIdentity identity = domainEvents.Cast <IDomainEvent <TAggregate, TIdentity> >().First().AggregateIdentity;
                eventsToApply = await _eventStore.LoadEventsAsync <TAggregate, TIdentity>(
                    identity,
                    (int)version + 1,
                    cancellationToken)
                                .ConfigureAwait(false);

                Log.Verbose(() =>
                            $"Read model '{typeof(TReadModel)}' with ID '{readModelEnvelope.ReadModelId}' is missing some events {version} < {expectedVersion}, adding them (got {eventsToApply.Count} events)");
            }
            else
            {
                eventsToApply = domainEvents;
                Log.Verbose(() =>
                            $"Read model '{typeof(TReadModel)}' with ID '{readModelEnvelope.ReadModelId}' has version {expectedVersion} (or none), applying events");
            }

            return(await ApplyUpdatesAsync(
                       readModelContext,
                       eventsToApply,
                       readModelEnvelope,
                       cancellationToken)
                   .ConfigureAwait(false));
        }
示例#5
0
        protected override async Task <ReadModelEnvelope <TReadModel> > UpdateAsync(
            IReadModelContext readModelContext,
            IReadOnlyCollection <IDomainEvent> domainEvents,
            ReadModelEnvelope <TReadModel> readModelEnvelope,
            CancellationToken cancellationToken)
        {
            var readModel = readModelEnvelope.ReadModel ?? await ReadModelFactory.CreateAsync(readModelEnvelope.ReadModelId, cancellationToken).ConfigureAwait(false);

            await ReadModelDomainEventApplier.UpdateReadModelAsync(readModel, domainEvents, readModelContext, cancellationToken).ConfigureAwait(false);

            var readModelVersion = domainEvents.Max(e => e.AggregateSequenceNumber);

            return(ReadModelEnvelope <TReadModel> .With(readModelEnvelope.ReadModelId, readModel, readModelVersion));
        }
示例#6
0
        private async Task <ReadModelUpdateResult <TReadModel> > ApplyUpdatesAsync(
            IReadModelContext readModelContext,
            IReadOnlyCollection <IDomainEvent> domainEvents,
            ReadModelEnvelope <TReadModel> readModelEnvelope,
            CancellationToken cancellationToken)
        {
            TReadModel readModel = await GetOrCreateReadModel(readModelEnvelope, cancellationToken);

            await ReadModelDomainEventApplier
            .UpdateReadModelAsync(readModel, domainEvents, readModelContext, cancellationToken)
            .ConfigureAwait(false);

            var readModelVersion = Math.Max(
                domainEvents.Max(e => e.AggregateSequenceNumber),
                readModelEnvelope.Version.GetValueOrDefault());

            return(readModelEnvelope.AsModifedResult(readModel, readModelVersion));
        }
示例#7
0
 protected abstract Task <ReadModelEnvelope <TReadModel> > UpdateAsync(
     IReadModelContext readModelContext,
     IReadOnlyCollection <IDomainEvent> domainEvents,
     ReadModelEnvelope <TReadModel> readModelEnvelope,
     CancellationToken cancellationToken);
示例#8
0
        protected override async Task <ReadModelUpdateResult <TReadModel> > UpdateAsync(
            IReadModelContext readModelContext,
            IReadOnlyCollection <IDomainEvent> domainEvents,
            ReadModelEnvelope <TReadModel> readModelEnvelope,
            CancellationToken cancellationToken)
        {
            if (!domainEvents.Any())
            {
                throw new ArgumentException("No domain events");
            }

            var expectedVersion = domainEvents.Min(d => d.AggregateSequenceNumber) - 1;
            var envelopeVersion = readModelEnvelope.Version;

            IReadOnlyCollection <IDomainEvent> eventsToApply;

            if (envelopeVersion.HasValue && expectedVersion != envelopeVersion)
            {
                var version = envelopeVersion.Value;
                if (expectedVersion < version)
                {
                    if (Logger.IsEnabled(LogLevel.Trace))
                    {
                        Logger.LogTrace(
                            "Read model {ReadModelType} with ID {Id} already has version {Version} compared to {ExpectedVersion}, skipping",
                            typeof(TReadModel),
                            readModelEnvelope.ReadModelId,
                            version,
                            expectedVersion);
                    }

                    return(readModelEnvelope.AsUnmodifedResult());
                }

                // Apply missing events
                var identity = domainEvents.Cast <IDomainEvent <TAggregate, TIdentity> >().First().AggregateIdentity;
                eventsToApply = await _eventStore.LoadEventsAsync <TAggregate, TIdentity>(
                    identity,
                    (int)version + 1,
                    cancellationToken)
                                .ConfigureAwait(false);

                if (Logger.IsEnabled(LogLevel.Trace))
                {
                    Logger.LogTrace(
                        "Read model {ReadModelType} with ID {Id} is missing some events {Version} < {ExpectedVersion}, adding them (got {MissingEventCount} events)",
                        typeof(TReadModel).PrettyPrint(),
                        readModelEnvelope.ReadModelId,
                        version,
                        expectedVersion,
                        eventsToApply.Count);
                }
            }
            else
            {
                eventsToApply = domainEvents;
                if (Logger.IsEnabled(LogLevel.Trace))
                {
                    Logger.LogTrace(
                        "Read model {ReadModelType} with ID {Id} has version {ExpectedVersion} (or none), applying events",
                        typeof(TReadModel).PrettyPrint(),
                        readModelEnvelope.ReadModelId,
                        expectedVersion);
                }
            }

            return(await ApplyUpdatesAsync(
                       readModelContext,
                       eventsToApply,
                       readModelEnvelope,
                       cancellationToken)
                   .ConfigureAwait(false));
        }
        protected override async Task <ReadModelUpdateResult <TReadModel> > UpdateAsync(
            IReadModelContext readModelContext,
            IReadOnlyCollection <IDomainEvent> domainEvents,
            ReadModelEnvelope <TReadModel> readModelEnvelope,
            CancellationToken cancellationToken)
        {
            if (!domainEvents.Any())
            {
                throw new ArgumentException("No domain events");
            }

            var expectedVersion = domainEvents.Min(d => d.AggregateSequenceNumber) - 1;
            var version         = readModelEnvelope.Version;

            if (!version.HasValue || expectedVersion == version)
            {
                Log.Verbose(() => $"Read model '{typeof(TReadModel)}' with ID '{readModelEnvelope.ReadModelId}' has version {expectedVersion} (or none), applying events");
                return(await base.UpdateAsync(
                           readModelContext,
                           domainEvents,
                           readModelEnvelope,
                           cancellationToken)
                       .ConfigureAwait(false));
            }
            if (expectedVersion < version.Value)
            {
                Log.Verbose(() => $"Read model '{typeof(TReadModel)}' with ID '{readModelEnvelope.ReadModelId}' already has version {version.Value} compared to {expectedVersion}, skipping");
                return(readModelEnvelope.AsUnmodifedResult());
            }

            TReadModel readModel;

            if (readModelEnvelope.ReadModel == null)
            {
                readModel = await ReadModelFactory.CreateAsync(
                    readModelEnvelope.ReadModelId,
                    cancellationToken)
                            .ConfigureAwait(false);
            }
            else
            {
                readModel = readModelEnvelope.ReadModel;
            }

            // Apply missing events
            var identity      = domainEvents.Cast <IDomainEvent <TAggregate, TIdentity> >().First().AggregateIdentity;
            var missingEvents = await _eventStore.LoadEventsAsync <TAggregate, TIdentity>(
                identity,
                (int)version.Value + 1,
                cancellationToken)
                                .ConfigureAwait(false);

            Log.Verbose(() => $"Read model '{typeof(TReadModel)}' with ID '{readModelEnvelope.ReadModelId}' is missing some events {version.Value} < {expectedVersion}, adding them (got {missingEvents.Count} events)");

            await ReadModelDomainEventApplier.UpdateReadModelAsync(
                readModel,
                missingEvents,
                readModelContext,
                cancellationToken)
            .ConfigureAwait(false);

            version = domainEvents.Max(e => e.AggregateSequenceNumber);

            return(readModelEnvelope.AsModifedResult(
                       readModel,
                       version));
        }