Exemple #1
0
        public async Task <Result> StoreDomainEventAsync(IDomainEvent @event)
        {
            var evtType = @event.GetType();

            if (evtType.IsDefined(typeof(EventNotPersistedAttribute)))
            {
                return(Result.Ok());
            }
            try
            {
                if (_bufferInfo?.UseBuffer == true)
                {
                    await s_Lock.WaitAsync().ConfigureAwait(false);
                }
                using (var ctx = new EventStoreDbContext(_dbContextOptions, _archiveBehavior))
                {
                    await StoreEvent(@event, ctx).ConfigureAwait(false);

                    await ctx.SaveChangesAsync().ConfigureAwait(false);
                }
            }
            catch (Exception e)
            {
                _logger.LogErrorMultilines("EFEventStore : Unable to persist an event.", e.ToString());
                return(Result.Fail());
            }
            finally
            {
                s_Lock.Release();
            }
            return(Result.Ok());
        }
Exemple #2
0
        public async Task A_dynamic_projector_can_access_the_properties_of_unknown_event_types_dynamically()
        {
            using (var db = new EventStoreDbContext())
            {
                Enumerable.Range(1, 10).ForEach(i => db.Events.Add(new StorableEvent
                {
                    AggregateId = Guid.NewGuid(),
                    StreamName  = Any.CamelCaseName(),
                    Type        = Any.CamelCaseName(),
                    Body        = new { SomeValue = i }.ToJson()
                }));
                await db.SaveChangesAsync();
            }
            var total = 0;

            using (var catchup = CreateReadModelCatchup(Projector.CreateDynamic(e =>
            {
                total += (int)e.SomeValue;
            })))
            {
                await catchup.Run();
            }

            total.Should().Be(55);
        }
Exemple #3
0
 protected override async Task DeleteEventsFromEventStore(Guid aggregateId)
 {
     using (var db = new EventStoreDbContext())
     {
         db.Database.ExecuteSqlCommand(string.Format("DELETE FROM EventStore.Events WHERE AggregateId = '{0}'", aggregateId));
         await db.SaveChangesAsync();
     }
 }
Exemple #4
0
        public Task SaveEventAsync(IEvent @event, DbTransaction transaction)
        {
            if (transaction == null)
            {
                throw new ArgumentNullException("transaction", $"A {typeof(DbTransaction).FullName} is required as a pre-requisite to save the event.");
            }

            var eventEntry = FromEvent(@event);

            _eventStoreContext.Events.Add(eventEntry);
            if (null == _eventStoreContext.Database.CurrentTransaction)
            {
                _eventStoreContext.Database.UseTransaction(transaction);
            }

            return(_eventStoreContext.SaveChangesAsync());
        }
        private async Task StoreArchiveEventsAsync(IEnumerable <IDomainEvent> archiveEvents, EventStoreDbContext externalCtx)
        {
            switch (_archiveBehavior)
            {
            case SnapshotEventsArchiveBehavior.StoreToNewTable:
                using (var ctx = new EventStoreDbContext(_dbContextOptions))
                {
                    ctx.AddRange(archiveEvents.Select(GetArchiveEventFromIDomainEvent).ToList());
                    await ctx.SaveChangesAsync().ConfigureAwait(false);
                }
                break;

            case SnapshotEventsArchiveBehavior.StoreToNewDatabase:
                if (_archiveBehaviorDbContextOptions != null)
                {
                    using (var ctx = new ArchiveEventStoreDbContext(_archiveBehaviorDbContextOptions))
                    {
                        ctx.AddRange(
                            archiveEvents.Select(GetArchiveEventFromIDomainEvent));
                        await ctx.SaveChangesAsync().ConfigureAwait(false);
                    }
                }
                else
                {
                    throw new InvalidOperationException("EFEventStore.StoreDomainEventAsync() : Snapshot will be created and event to archive cannot be saved because DbContextOptions for archive database weren't provided during configuration on Bootstrapper. Either specify DbContextOptions for event's archive database or change archive behavior");
                }
                break;
            }
            var eventsInContext = externalCtx
                                  .ChangeTracker
                                  .Entries()
                                  .Where(e => e.State != EntityState.Detached && e.State != EntityState.Deleted)
                                  .Select(e => e.Entity as Event)
                                  .WhereNotNull()
                                  .Where(e => archiveEvents.Any(ev => ev.Id == e !.Id))
                                  .ToList();

            if (eventsInContext.Count > 0)
            {
                eventsInContext.DoForEach(e => externalCtx.Entry(e).State = EntityState.Detached);
            }
            using (var ctx = new EventStoreDbContext(_dbContextOptions))
            {
                var archiveEventsIds = archiveEvents.Select(e => e.Id).ToList();
                var events           = await ctx.Set <Event>().Where(e => archiveEventsIds.Contains(e.Id)).ToListAsync().ConfigureAwait(false);

                if (events.Count > 0)
                {
                    ctx.RemoveRange(events);
                    await ctx.SaveChangesAsync().ConfigureAwait(false);
                }
            }
        }
Exemple #6
0
 public static async Task SaveToEventStore <TAggregate>(this TAggregate aggregate) where TAggregate : EventSourcedAggregate
 {
     using (var db = new EventStoreDbContext())
     {
         foreach (var e in aggregate.EventHistory.OfType <IEvent <TAggregate> >())
         {
             var storableEvent = e.ToStorableEvent();
             db.Events.Add(storableEvent);
         }
         await db.SaveChangesAsync();
     }
 }
Exemple #7
0
        private async Task StoreArchiveEventsAsync(IEnumerable <IDomainEvent> archiveEvents, EventStoreDbContext externalCtx)
        {
            switch (_archiveBehavior)
            {
            case SnapshotEventsArchiveBehavior.StoreToNewTable:
                using (var ctx = new EventStoreDbContext(_dbContextOptions))
                {
                    ctx.AddRange(archiveEvents.Select(GetArchiveEventFromIDomainEvent).ToList());
                    await ctx.SaveChangesAsync().ConfigureAwait(false);
                }
                break;

            case SnapshotEventsArchiveBehavior.StoreToNewDatabase:
                using (var ctx = new ArchiveEventStoreDbContext(_archiveBehaviorDbContextOptions))
                {
                    ctx.AddRange(
                        archiveEvents.Select(GetArchiveEventFromIDomainEvent));
                    await ctx.SaveChangesAsync().ConfigureAwait(false);
                }
                break;
            }
            var eventsInContext = externalCtx
                                  .ChangeTracker
                                  .Entries()
                                  .Where(e => e.State != EntityState.Detached && e.State != EntityState.Deleted)
                                  .Select(e => e.Entity as Event)
                                  .WhereNotNull()
                                  .Where(e => archiveEvents.Any(ev => ev.Id == e.Id))
                                  .ToList();

            if (eventsInContext.Count > 0)
            {
                eventsInContext.DoForEach(e => externalCtx.Entry(e).State = EntityState.Detached);
            }
            using (var ctx = new EventStoreDbContext(_dbContextOptions))
            {
                var archiveEventsIds = archiveEvents.Select(e => e.Id).ToList();
                var events           = await ctx.Set <Event>().Where(e => archiveEventsIds.Contains(e.Id)).ToListAsync().ConfigureAwait(false);

                if (events.Count > 0)
                {
                    ctx.RemoveRange(events);
                    await ctx.SaveChangesAsync().ConfigureAwait(false);
                }
            }
        }
Exemple #8
0
        public async Task Duck_projectors_can_access_the_event_properties_of_received_events()
        {
            var expectedTimestamp       = DateTimeOffset.Parse("2014-07-03");
            var expectedAggregateId     = Any.Guid();
            var receivedAggregateId     = new Guid();
            var expectedSequenceNumber  = Any.PositiveInt();
            int receivedSequenceNumber  = 0;
            var receivedTimestamp       = new DateTimeOffset();
            var receivedEventStreamName = "";
            var receivedEventTypeName   = "";

            using (var db = new EventStoreDbContext())
            {
                db.Events.Add(new StorableEvent
                {
                    AggregateId    = expectedAggregateId,
                    SequenceNumber = expectedSequenceNumber,
                    Timestamp      = expectedTimestamp,
                    StreamName     = "Reporting",
                    Type           = "DuckEvent",
                    Body           = new { Quacks = 9000 }.ToJson()
                });

                await db.SaveChangesAsync();
            }

            var projector = Projector.CreateFor <Reporting.DuckEvent>(e =>
            {
                receivedAggregateId     = e.AggregateId;
                receivedSequenceNumber  = e.SequenceNumber;
                receivedTimestamp       = e.Timestamp;
                receivedEventStreamName = e.EventStreamName;
                receivedEventTypeName   = e.EventTypeName;
            });

            using (var catchup = CreateReadModelCatchup(projector))
            {
                await catchup.Run();
            }

            receivedAggregateId.Should().Be(expectedAggregateId);
            receivedSequenceNumber.Should().Be(expectedSequenceNumber);
            receivedTimestamp.Should().Be(expectedTimestamp);
            receivedEventStreamName.Should().Be("Reporting");
            receivedEventTypeName.Should().Be("DuckEvent");
        }
Exemple #9
0
        public async Task When_classes_not_implementing_IEvent_are_used_to_query_the_event_store_then_nested_classes_can_be_used_to_specify_stream_names()
        {
            using (var db = new EventStoreDbContext())
            {
                Enumerable.Range(1, 5).ForEach(i => db.Events.Add(new StorableEvent
                {
                    AggregateId = Guid.NewGuid(),
                    StreamName  = "Reporting",
                    Type        = "DuckEvent",
                    Body        = new { Quacks = i }.ToJson()
                }));

                Enumerable.Range(1, 5).ForEach(i => db.Events.Add(new StorableEvent
                {
                    AggregateId = Guid.NewGuid(),
                    StreamName  = Any.CamelCaseName(),
                    Type        = "DuckEvent",
                    Body        = new { Quacks = i }.ToJson()
                }));

                await db.SaveChangesAsync();
            }
            var unNestedDucks = 0;
            var nestedDucks   = 0;

            var projector1 = Projector.CreateFor <DuckEvent>(e =>
            {
                unNestedDucks++;
            });
            var projector2 = Projector.CreateFor <Reporting.DuckEvent>(e =>
            {
                nestedDucks++;
            });

            using (var catchup = CreateReadModelCatchup(projector1, projector2))
            {
                await catchup.Run();
            }

            nestedDucks.Should().Be(5);
            unNestedDucks.Should().Be(10);
        }
        public async Task Save(IEnumerable <IEvent> events, CancellationToken cancellationToken = default(CancellationToken))
        {
            foreach (var @event in events)
            {
                var eventEntity = FromEvent(@event);

                _eventStoreContext.Events.Add(eventEntity);

                await _publisher.Publish(@event, cancellationToken);

                //eventEntity.Version++;
                eventEntity.State = EventStateEnum.Published;

                //eventEntity.State = EventStateEnum.Published;
                //eventEntity.Version++;
            }
            ;

            await _eventStoreContext.SaveChangesAsync();
        }
        public async Task Events_that_cannot_be_deserialized_to_the_expected_type_are_logged_as_EventHandlingErrors()
        {
            var badEvent = new StorableEvent
            {
                Actor      = Any.Email(),
                StreamName = typeof(Order).Name,
                Type       = typeof(Order.ItemAdded).Name,
                Body       = new { Price = "oops this is not a number" }.ToJson(),
                SequenceNumber = Any.PositiveInt(),
                AggregateId    = Any.Guid(),
                UtcTime        = DateTime.UtcNow
            };

            using (var eventStore = new EventStoreDbContext())
            {
                eventStore.Events.Add(badEvent);
                await eventStore.SaveChangesAsync();
            }

            using (var catchup = CreateReadModelCatchup(new Projector1()))
            {
                await catchup.Run();
            }

            using (var readModels = new ReadModelDbContext())
            {
                var failure = readModels.Set <EventHandlingError>()
                              .OrderByDescending(e => e.Id)
                              .First(e => e.AggregateId == badEvent.AggregateId);
                failure.Error.Should().Contain("JsonReaderException");
                failure.SerializedEvent.Should().Contain(badEvent.Body);
                failure.Actor.Should().Be(badEvent.Actor);
                failure.OriginalId.Should().Be(badEvent.Id);
                failure.AggregateId.Should().Be(badEvent.AggregateId);
                failure.SequenceNumber.Should().Be(badEvent.SequenceNumber);
                failure.StreamName.Should().Be(badEvent.StreamName);
                failure.EventTypeName.Should().Be(badEvent.Type);
            }
        }
Exemple #12
0
        public async Task <Result> StoreDomainEventRangeAsync(IEnumerable <IDomainEvent> events)
        {
            if (events?.Any() == false)
            {
                return(Result.Fail());
            }

            try
            {
                var eventsByAggregateGroup
                    = events
                      .GroupBy(e => e.AggregateId ?? 0)
                      .Select(g => new { AggregateId = g.Key, Events = g.ToList() })
                      .ToList();
                var tasks = new List <Task>();
                foreach (var evtGroups in eventsByAggregateGroup)
                {
                    tasks.Add(Task.Run(async() =>
                    {
                        using (var ctx = new EventStoreDbContext(_dbContextOptions, _archiveBehavior))
                        {
                            foreach (var evt in evtGroups.Events)
                            {
                                await StoreEvent(evt, ctx, false).ConfigureAwait(false);
                            }
                            await ctx.SaveChangesAsync();
                        }
                    }));
                }
                await Task.WhenAll(tasks);
            }
            catch (Exception e)
            {
                _logger.LogErrorMultilines("EFEventStore : Unable to persist a collection of events.", e.ToString());
                return(Result.Fail());
            }
            return(Result.Ok());
        }
Exemple #13
0
        protected override async Task SaveEventsDirectly(params IStoredEvent[] events)
        {
            var storableEvents =
                events.Select(
                    e =>
                    new StorableEvent
            {
                AggregateId    = Guid.Parse(e.AggregateId),
                Body           = e.Body,
                ETag           = e.ETag,
                SequenceNumber = e.SequenceNumber,
                StreamName     = e.StreamName,
                Timestamp      = e.Timestamp,
                Type           = e.Type,
                UtcTime        = e.Timestamp.UtcDateTime
            });

            using (var db = new EventStoreDbContext())
            {
                db.Events.AddRange(storableEvents);
                await db.SaveChangesAsync();
            }
        }
Exemple #14
0
        public async Task StoreAsync(StoredEvent theEvent)
        {
            await _context.StoredEvents.AddAsync(theEvent);

            await _context.SaveChangesAsync();
        }