public async Task SaveAsync(Type aggregateType, IAggregateIdentity aggregateId, ICollection<IEvent> events, CancellationToken cancellationToken = default(CancellationToken)) { if (events.Count == 0) return; var serialized = events.Select(ToEventData).ToArray(); Stream stream; if (!openStreams.TryGetValue(aggregateId, out stream)) { var aggregateTypeName = aggregateType.Name; var partition = GetPartition(aggregateTypeName, aggregateId); stream = new Stream(partition); openStreams.Add(aggregateId, stream); } // Save the events try { var result = await StreamWriteAsync(stream, serialized); openStreams[aggregateId] = result.Stream; } catch (ConcurrencyConflictException ex) { throw new Ddd.Domain.Exceptions.ConcurrencyException(aggregateType, aggregateId, ex); } // Publish events (sync the read side) await bus.PublishAsync(events, default(CancellationToken)); }
private Partition GetPartition(string aggregateTypeName, IAggregateIdentity aggregateId) { var table = tableClient.GetTableReference(aggregateTypeName); //return new Partition(table, string.Format("{0}|{1}", typeof(TAggregate).Name, aggId.ToString())); return(new Partition(table, aggregateId.Value)); }
public async Task SaveAsync(Type aggregateType, IAggregateIdentity aggregateId, ICollection <IEvent> events, CancellationToken cancellationToken = default(CancellationToken)) { if (events.Count == 0) { return; } var serialized = events.Select(ToEventData).ToArray(); Stream stream; if (!openStreams.TryGetValue(aggregateId, out stream)) { var aggregateTypeName = aggregateType.Name; var partition = GetPartition(aggregateTypeName, aggregateId); stream = new Stream(partition); openStreams.Add(aggregateId, stream); } // Save the events try { var result = await StreamWriteAsync(stream, serialized); openStreams[aggregateId] = result.Stream; } catch (ConcurrencyConflictException ex) { throw new Ddd.Domain.Exceptions.ConcurrencyException(aggregateType, aggregateId, ex); } // Publish events (sync the read side) await bus.PublishAsync(events, default(CancellationToken)); }
public void Add(IAggregateIdentity id, IList <IEvent> changes) { using (var connection = database.Connection) { connection.Add(id, changes); } }
public IEnumerable <IEvent> Get(IAggregateIdentity id) { using (var connection = database.Connection) { return(connection.Get(id)); } }
public IEnumerable <IEvent> Get(IAggregateIdentity id) { if (events.ContainsKey(id.ToString())) { return(events[id.ToString()]); } return(new List <IEvent>()); }
public async Task <ICollection <IEvent> > GetAsync(Type aggregateType, IAggregateIdentity aggregateId, int fromVersion = 1, CancellationToken cancellationToken = default(CancellationToken)) { if (initialEvents != null) { ProcessAndClearInitialEvents(); } return(await decorated.GetAsync(aggregateType, aggregateId, fromVersion, cancellationToken)); }
protected async Task Update(IAggregateIdentity id, Action <T> execute) { var events = eventStore.Get(id); var aggregate = BuildAggregate(events); execute(aggregate); eventStore.Add(id, aggregate.Changes); await ViewStore.Update(id, aggregate.Changes); }
public async Task Update(IAggregateIdentity id, IList <IEvent> changes) { foreach (var @event in changes) { foreach (var handler in eventHandlers.Values.Where(h => h.CanHandle(@event))) { await handler.Update(id, @event); } } }
async Task HandleMeasurementUnitChanged(IAggregateIdentity id, IEvent @event) { if (@event is MeasurementUnitChanged measurementEvent) { var viewModel = await Repository.GetAsync(id.Guid); viewModel.Unit = measurementEvent.Unit; await Repository.UpdateAsync(viewModel); } }
async Task HandleMeasurementValueAdded(IAggregateIdentity id, IEvent @event) { if (@event is MeasurementValueAdded measurementEvent) { var viewModel = await Repository.GetAsync(id.Guid); viewModel.Values.Add(measurementEvent.OccurredOn, measurementEvent.Value); await Repository.UpdateAsync(viewModel); } }
private async Task ActivateChallenge(IAggregateIdentity id, IEvent @event) { if (@event is ChallengeActivated changeEvent) { var viewModel = await Repository.GetAsync(id.Guid); viewModel.IsPaused = false; await Repository.UpdateAsync(viewModel); } }
async Task AddRepetitions(IAggregateIdentity id, IEvent @event) { if (@event is WorkoutExecuted changeEvent) { var viewModel = await Repository.GetAsync(changeEvent.ChallengeId.Guid); viewModel.TotalRepetitions += changeEvent.Repetitions; await Repository.UpdateAsync(viewModel); } }
private async Task ChangeDailyRepetitions(IAggregateIdentity id, IEvent @event) { if (@event is DailyRepetitionsChanged dailyRepetitionsChanged) { var viewModel = await Repository.GetAsync(id.Guid); viewModel.DailyRepetitions = dailyRepetitionsChanged.Repetitions; await Repository.UpdateAsync(viewModel); } }
private async Task ChangeDescription(IAggregateIdentity id, IEvent @event) { if (@event is ChallengeDescriptionChanged descriptionChanged) { var viewModel = await Repository.GetAsync(id.Guid); viewModel.Desciption = descriptionChanged.Description; await Repository.UpdateAsync(viewModel); } }
async Task SetWorkoutExecuted(IAggregateIdentity id, IEvent @event) { if (@event is WorkoutExecuted workoutExecuted) { var viewModel = await Repository.GetAsync(id.Guid); viewModel.Executed = true; viewModel.PerformedOn = workoutExecuted.OccurredOn; await Repository.UpdateAsync(viewModel); } }
public async Task SaveAsync(Type aggregateType, IAggregateIdentity aggregateId, ICollection <IEvent> events, CancellationToken cancellationToken = default(CancellationToken)) { if (initialEvents != null) { ProcessAndClearInitialEvents(); } await decorated.SaveAsync(aggregateType, aggregateId, events, cancellationToken); newEvents.Set(aggregateType, aggregateId, events); }
public void Add(IAggregateIdentity id, IList <IEvent> changes) { if (events.ContainsKey(id.ToString())) { events[id.ToString()].AddRange(changes); } else { events.Add(id.ToString(), changes as List <IEvent>); } }
private async Task PauseChallenge(IAggregateIdentity id, IEvent @event) { if (@event is ChallengePaused changeEvent) { var viewModel = await Repository.GetAsync(id.Guid); viewModel.IsPaused = true; viewModel.PausedDateTime = changeEvent.OccurredOn; viewModel.PausedDuration = changeEvent.Duration; await Repository.UpdateAsync(viewModel); } }
async Task CreateMeasurement(IAggregateIdentity id, IEvent @event) { if (@event is MeasurementCreated measurementCreated) { var viewModel = new MeasurementViewModel { Id = measurementCreated.Id.Guid, Type = measurementCreated.Type, Unit = measurementCreated.Unit, }; await Repository.AddAsync(viewModel); } }
async Task CreateView(IAggregateIdentity id, IEvent @event) { if (@event is WorkoutCreated workoutCreated) { var viewModel = new WorkoutViewModel { Id = workoutCreated.Id.Guid, Reps = workoutCreated.Reps, WorkoutType = workoutCreated.Type.ToString() }; await Repository.AddAsync(viewModel); } }
private async Task CreateView(IAggregateIdentity id, IEvent @event) { if (@event is ChallengeCreated challengeCreated) { await Repository.AddAsync(new ChallengeViewModel { Id = challengeCreated.Id.Guid, StartDate = challengeCreated.OccurredOn, Desciption = challengeCreated.Description, DailyRepetitions = challengeCreated.Repetitions }); } }
private async Task ChangeRestingCycle(IAggregateIdentity id, IEvent @event) { if (@event is RestingCycleChanged changeEvent) { var viewModel = await Repository.GetAsync(id.Guid); viewModel.ActiveMonday = changeEvent.RestingCycle[1]; viewModel.ActiveTuesday = changeEvent.RestingCycle[2]; viewModel.ActiveWednesday = changeEvent.RestingCycle[3]; viewModel.ActiveThursday = changeEvent.RestingCycle[4]; viewModel.ActiveFriday = changeEvent.RestingCycle[5]; viewModel.ActiveSaturday = changeEvent.RestingCycle[6]; viewModel.ActiveSunday = changeEvent.RestingCycle[7]; await Repository.UpdateAsync(viewModel); } }
public async Task SaveAsync(Type aggregateType, IAggregateIdentity aggregateId, ICollection <IEvent> events, CancellationToken cancellationToken = default(CancellationToken)) { if (events.Count == 0) { return; } var partition = GetPartition(aggregateType, aggregateId); lock (eventStore) { Tuple <ETag, List <EventEntity> > eTaggedEvents; if (eventStore.TryGetValue(partition, out eTaggedEvents)) { // Check my last ETag against the current ETag var dbETag = eTaggedEvents.Item1; ETag myETag; if (idToETag.TryGetValue(aggregateId, out myETag) && myETag != dbETag) { throw new Ddd.Domain.Exceptions.ConcurrencyException(aggregateType, aggregateId); } var eventsEntities = eTaggedEvents.Item2; var lastVer = eventsEntities.Count; eventsEntities.AddRange(events.Select(e => ToEventEntity(e, ++lastVer))); var eTag = ETag.NewGuid(); eventStore[partition] = new Tuple <ETag, List <EventEntity> >( eTag, eventsEntities); idToETag[aggregateId] = eTag; // Remeber current ETag } else { var eTag = ETag.NewGuid(); var lastVer = 0; var eventsEntities = events.Select(e => ToEventEntity(e, ++lastVer)).ToList(); eventStore.Add(partition, new Tuple <ETag, List <EventEntity> >( eTag, eventsEntities)); idToETag.Add(aggregateId, eTag); // Remeber current ETag } } await bus.PublishAsync(events); }
public async Task SaveAsync(Type aggregateType, IAggregateIdentity aggregateId, ICollection<IEvent> events, CancellationToken cancellationToken = default(CancellationToken)) { if (events.Count == 0) return; var partition = GetPartition(aggregateType, aggregateId); lock (eventStore) { Tuple<ETag, List<EventEntity>> eTaggedEvents; if (eventStore.TryGetValue(partition, out eTaggedEvents)) { // Check my last ETag against the current ETag var dbETag = eTaggedEvents.Item1; ETag myETag; if (idToETag.TryGetValue(aggregateId, out myETag) && myETag != dbETag) { throw new Ddd.Domain.Exceptions.ConcurrencyException(aggregateType, aggregateId); } var eventsEntities = eTaggedEvents.Item2; var lastVer = eventsEntities.Count; eventsEntities.AddRange(events.Select(e => ToEventEntity(e, ++lastVer))); var eTag = ETag.NewGuid(); eventStore[partition] = new Tuple<ETag, List<EventEntity>>( eTag, eventsEntities); idToETag[aggregateId] = eTag; // Remeber current ETag } else { var eTag = ETag.NewGuid(); var lastVer = 0; var eventsEntities = events.Select(e => ToEventEntity(e, ++lastVer)).ToList(); eventStore.Add(partition, new Tuple<ETag, List<EventEntity>>( eTag, eventsEntities)); idToETag.Add(aggregateId, eTag); // Remeber current ETag } } await bus.PublishAsync(events); }
public void AppendEvents(IAggregateIdentity aggregateId, IEnumerable<IEvent> eventsToAppend) { using (var conn = new SqlConnection(_connectionString)) { using (var cmd = new SqlCommand(InsertEventsQuery, conn)) { cmd.Parameters.AddWithValue("@aggregateId", aggregateId.GetId()); cmd.Parameters.AddWithValue("@aggregateIdTag", aggregateId.GetTag()); var dataParameter = cmd.Parameters.Add("@eventData", SqlDbType.VarBinary); conn.Open(); foreach (var eventData in eventsToAppend.Select(_serializer.Serialize)) { dataParameter.Value = eventData; cmd.ExecuteNonQuery(); } } } }
public Task <bool> TryRemoveUniqueValueKey(string valueGroup, string value, IAggregateIdentity key, bool ignoreCase = true) { if (string.IsNullOrEmpty(valueGroup)) { throw new ArgumentNullException("valueGroup"); } if (string.IsNullOrEmpty(value)) { throw new ArgumentNullException("value"); } ConcurrentDictionary <string, IAggregateIdentity> groupValues; if (!groups.TryGetValue(valueGroup, out groupValues)) { return(Task.FromResult(false)); } IAggregateIdentity removedKey; return(Task.FromResult(groupValues.TryRemove(value, out removedKey))); }
public Task<ICollection<IEvent>> GetAsync(Type aggregateType, IAggregateIdentity aggregateId, int fromVersion = 1, CancellationToken cancellationToken = default(CancellationToken)) { var partition = GetPartition(aggregateType, aggregateId); lock (eventStore) { Tuple<ETag, List<EventEntity>> eTaggedEvents; if (!eventStore.TryGetValue(partition, out eTaggedEvents)) return Task.FromResult<ICollection<IEvent>>(new IEvent[0]); var eTag = eTaggedEvents.Item1; var storedEvents = eTaggedEvents.Item2; idToETag[aggregateId] = eTag; var deserializedEvents = storedEvents .Skip(fromVersion - 1) .Select(DeserializeEvent) .ToList(); return Task.FromResult<ICollection<IEvent>>(deserializedEvents); } }
public async Task <ICollection <IEvent> > GetAsync(Type aggregateType, IAggregateIdentity aggregateId, int fromVersion = 1, CancellationToken cancellationToken = default(CancellationToken)) { var aggregateTypeName = aggregateType.Name; tableClient.GetTableReference(aggregateTypeName).CreateIfNotExists(); var partition = GetPartition(aggregateTypeName, aggregateId); //Stream stream; // Open the stream and keep a reference to it for fufure writes of the same aggregate. if (!openStreams.ContainsKey(aggregateId)) { var existent = await Stream.TryOpenAsync(partition); if (!existent.Found) { openStreams.Add(aggregateId, new Stream(partition)); return(new List <IEvent>(0)); } openStreams.Add(aggregateId, existent.Stream); } StreamSlice <EventEntity> slice; var nextSliceStart = fromVersion; var events = new List <IEvent>(1000); do { slice = await Stream.ReadAsync <EventEntity>(partition, nextSliceStart, sliceSize : 1); nextSliceStart = nextSliceStart = slice.HasEvents ? slice.Events.Last().Version + 1 : -1; events.AddRange(slice.Events.Select(DeserializeEvent)); }while (!slice.IsEndOfStream); return(events); }
public Task <ICollection <IEvent> > GetAsync(Type aggregateType, IAggregateIdentity aggregateId, int fromVersion = 1, CancellationToken cancellationToken = default(CancellationToken)) { var partition = GetPartition(aggregateType, aggregateId); lock (eventStore) { Tuple <ETag, List <EventEntity> > eTaggedEvents; if (!eventStore.TryGetValue(partition, out eTaggedEvents)) { return(Task.FromResult <ICollection <IEvent> >(new IEvent[0])); } var eTag = eTaggedEvents.Item1; var storedEvents = eTaggedEvents.Item2; idToETag[aggregateId] = eTag; var deserializedEvents = storedEvents .Skip(fromVersion - 1) .Select(DeserializeEvent) .ToList(); return(Task.FromResult <ICollection <IEvent> >(deserializedEvents)); } }
public IEnumerable<IEvent> GetEventsFor(IAggregateIdentity aggregateId, int version) { using (var conn = new SqlConnection(_connectionString)) { using (var cmd = new SqlCommand(SelectEventsQuery, conn)) { cmd.Parameters.AddWithValue("@aggregateId", aggregateId.GetId()); cmd.Parameters.AddWithValue("@aggregateIdTag", aggregateId.GetTag()); cmd.Parameters.AddWithValue("@version", version); conn.Open(); using (var reader = cmd.ExecuteReader()) { var events = new List<IEvent>(); while (reader.Read()) { var eventData = reader.GetSqlBinary(reader.GetOrdinal("EventData")).Value; events.Add(_serializer.Deserialize(eventData)); } return events; } } } }
public static string Value(this IAggregateIdentity id) { return(id.Value); }
public Task <bool> TryRemoveUniqueValueKey(string valueGroup, string value, IAggregateIdentity key, bool ignoreCase = true) { throw new NotImplementedException(); }
public int GetVersionFor(IAggregateIdentity aggregateId) { return _versionCache.GetOrAdd(aggregateId, GetVersionFromFile); }
public int GetVersionFor(IAggregateIdentity aggregateId) { Contract.Requires<ArgumentNullException>(aggregateId != null, "aggregateId cannot be null"); throw new NotImplementedException(); }
public int GetVersionFor(IAggregateIdentity aggregateId) { using (var conn = new SqlConnection(_connectionString)) { using (var cmd = new SqlCommand(CountEventsQuery, conn)) { cmd.Parameters.AddWithValue("@aggregateId", aggregateId.GetId()); cmd.Parameters.AddWithValue("@aggregateIdTag", aggregateId.GetTag()); conn.Open(); return (int)cmd.ExecuteScalar(); } } }
public void AppendEvents(IAggregateIdentity aggregateId, IEnumerable<IEvent> eventsToAppend) { using (var writer = GetWriter(aggregateId)) { foreach (var eventData in eventsToAppend.Select(_serializer.Serialize)) { writer.Write(eventData.Length); writer.Write(eventData); } } }
public AggregateNotFoundException(Type aggregateType, IAggregateIdentity id) : base(string.Format("Aggregate {0} with id {1} was not found.", aggregateType.FullName, id)) { }
public void AppendEventsToStream(IAggregateIdentity aggregateId, int expectedVersion, IEvent[] eventsToAppend) { if(!eventsToAppend.Any()) return; var actualVersion = _persistance.GetVersionFor(aggregateId); if (actualVersion != expectedVersion) { var committedEvents = _persistance.GetEventsFor(aggregateId).Skip(expectedVersion).ToList(); if (_conflictDetector.HasConflict(committedEvents, eventsToAppend)) throw new AggregateConcurrencyException(expectedVersion, actualVersion); AppendEventsToStream(aggregateId, expectedVersion + committedEvents.Count, eventsToAppend); return; } _persistance.AppendEvents(aggregateId, eventsToAppend); _publisher.Publish(eventsToAppend); }
public void AppendEvents(IAggregateIdentity aggregateId, IEnumerable<IEvent> eventsToAppend) { var eventData = eventsToAppend.Select(_serializer.Serialize); EventsFor(aggregateId).AddRange(eventData); }
private void SetCachedVersion(IAggregateIdentity aggregateId, int version) { _versionCache.AddOrUpdate(aggregateId, version, (i, c) => version); }
public void AppendEvents(IAggregateIdentity aggregateId, IEnumerable<IEvent> eventsToAppend) { Contract.Requires<ArgumentNullException>(aggregateId != null, "aggregateId cannot be null"); Contract.Requires<ArgumentNullException>(eventsToAppend != null, "eventsToAppend cannot be null"); Contract.Requires<ArgumentException>(Contract.ForAll(eventsToAppend, e => e != null), "none of the events in eventsToAppend can be null"); }
public IEnumerable<IEvent> GetEventsFor(IAggregateIdentity aggregateId, int version) { Contract.Requires<ArgumentNullException>(aggregateId != null, "aggregateId cannot be null"); Contract.Requires<ArgumentOutOfRangeException>(version >= 0, "version cannot be negative"); throw new NotImplementedException(); }
private static string GetPartition(Type aggregateType, IAggregateIdentity aggregateId) { return string.Concat(aggregateType.FullName, "|", aggregateId.ToString()); }
public IEnumerable<IEvent> GetEventsFor(IAggregateIdentity aggregateId, int version) { var eventData = EventsFor(aggregateId).Take(version).ToList(); return eventData.Select(_serializer.Deserialize); }
private List<byte[]> EventsFor(IAggregateIdentity aggregateId) { return _events.GetOrAdd(aggregateId, new List<byte[]>()); }
public async Task Update(IAggregateIdentity id, IEvent @event) { await Actions[@event.GetType().Name](id, @event); }
private BinaryReader GetReader(IAggregateIdentity aggregateId) { var fileStream = File.Open(GetFilePath(aggregateId), FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read); return new BinaryReader(fileStream); }
public IEnumerable<IEvent> GetEventsFor(IAggregateIdentity aggregateId, int version) { var events = new List<IEvent>(); using (var reader = GetReader(aggregateId)) { while (reader.PeekChar() > -1 && events.Count < version) { var dataLength = reader.ReadInt32(); var data = reader.ReadBytes(dataLength); events.Add(_serializer.Deserialize(data)); } } SetCachedVersion(aggregateId, events.Count); return events; }
private string GetFilePath(IAggregateIdentity aggregateId) { var filePath = Path.Combine(_storagePath, String.Concat(aggregateId.GetTag(), aggregateId.GetId())); return filePath; }
public void Set(Type aggregateType, IAggregateIdentity aggregateId, ICollection <IEvent> events) => savedEvents.Add(Tuple.Create(aggregateType, aggregateId, events));
public void AppendEventsToStream(IAggregateIdentity aggregateId, int expectedVersion, IEvent[] eventsToAppend) { Contract.Requires<ArgumentNullException>(aggregateId != null, "aggregateId cannot be null"); Contract.Requires<ArgumentOutOfRangeException>(expectedVersion >= 0, "expectedVersion cannot be negative"); Contract.Requires<ArgumentNullException>(eventsToAppend != null, "eventsToAppend cannot be null"); Contract.Requires<ArgumentNullException>(Contract.ForAll(eventsToAppend, e => e != null), "None of the events in eventsToAppend can be null"); throw new NotImplementedException(); }
private BinaryWriter GetWriter(IAggregateIdentity aggregateId) { var fileStream = File.Open(GetFilePath(aggregateId), FileMode.Append, FileAccess.Write, FileShare.None); return new BinaryWriter(fileStream); }
private int GetVersionFromFile(IAggregateIdentity aggregateId) { // TODO : Need a more efficient way to store version. Separate file? End of file? var version = 0; using (var reader = GetReader(aggregateId)) { while (reader.PeekChar() > -1) { var dataLength = reader.ReadInt32(); reader.BaseStream.Position += dataLength; version++; } } return version; }
private Partition GetPartition(string aggregateTypeName, IAggregateIdentity aggregateId) { var table = tableClient.GetTableReference(aggregateTypeName); //return new Partition(table, string.Format("{0}|{1}", typeof(TAggregate).Name, aggId.ToString())); return new Partition(table, aggregateId.Value); }
public int GetVersionFor(IAggregateIdentity aggregateId) { return EventsFor(aggregateId).Count; }
public async Task<ICollection<IEvent>> GetAsync(Type aggregateType, IAggregateIdentity aggregateId, int fromVersion = 1, CancellationToken cancellationToken = default(CancellationToken)) { var aggregateTypeName = aggregateType.Name; tableClient.GetTableReference(aggregateTypeName).CreateIfNotExists(); var partition = GetPartition(aggregateTypeName, aggregateId); //Stream stream; // Open the stream and keep a reference to it for fufure writes of the same aggregate. if (!openStreams.ContainsKey(aggregateId)) { var existent = await Stream.TryOpenAsync(partition); if (!existent.Found) { openStreams.Add(aggregateId, new Stream(partition)); return new List<IEvent>(0); } openStreams.Add(aggregateId, existent.Stream); } StreamSlice<EventEntity> slice; var nextSliceStart = fromVersion; var events = new List<IEvent>(1000); do { slice = await Stream.ReadAsync<EventEntity>(partition, nextSliceStart, sliceSize: 1); nextSliceStart = nextSliceStart = slice.HasEvents ? slice.Events.Last().Version + 1 : -1; events.AddRange(slice.Events.Select(DeserializeEvent)); } while (!slice.IsEndOfStream); return events; }
public EventStream GetEventStreamFor(IAggregateIdentity aggregateId, int version) { var events = _persistance.GetEventsFor(aggregateId, version).ToList(); return new EventStream { StreamVersion = events.Count(), Events = events }; }