/// <summary> /// This is a very special way to interact with an aggregate, it is the standard pattern /// where a command handler load an aggregate, invokes some methods on it then save. /// It can use cached instance of <see cref="IAggregateCachedRepository{TAggregate}"/> thus /// achieving really faster performances. /// </summary> /// <param name="id"></param> /// <param name="callback"></param> /// <param name="createIfNotExists"></param> protected void FindAndModify(EventStoreIdentity id, Action <TAggregate> callback, bool createIfNotExists = false) { if (JarvisFrameworkGlobalConfiguration.SingleAggregateRepositoryCacheEnabled) { //Lock is NEEDED because multiple thread cannot access the very same aggregate. lock (NamedLocker.Instance.GetLock(id.Id)) { using (var repo = AggregateCachedRepositoryFactory.Create <TAggregate>(id)) { var aggregate = repo.Aggregate; if (!createIfNotExists && aggregate.Version == 0) { throw new UninitializedAggregateException(); } SetupContext(aggregate); callback(aggregate); repo.Save(_commitId, StoreCommandHeaders); } } } else { //This is the classic command execution, each execution reload the entity and stream. var aggregate = Repository.GetById <TAggregate>(id); if (!createIfNotExists && aggregate.Version == 0) { throw new UninitializedAggregateException(); } SetupContext(aggregate); callback(aggregate); Repository.Save(aggregate, _commitId, StoreCommandHeaders); } }
/// <summary> /// This is a very special way to interact with an aggregate, it is the standard pattern /// where a command handler load an aggregate, invokes some methods on it then save. /// It can use cached instance of <see cref="IAggregateCachedRepository{TAggregate}"/> thus /// achieving really faster performances. /// </summary> /// <param name="id"></param> /// <param name="callback"></param> /// <param name="createIfNotExists"></param> protected virtual async Task FindAndModifyAsync( EventStoreIdentity id, Func <TAggregate, Task <RepositoryCommandHandlerCallbackReturnValue> > callback, bool createIfNotExists = false) { if (JarvisFrameworkGlobalConfiguration.SingleAggregateRepositoryCacheEnabled) { //Lock is NEEDED because multiple thread cannot access the very same aggregate. lock (NamedLocker.Instance.GetLock(id.Id)) { using (var repo = AggregateCachedRepositoryFactory.Create <TAggregate>(id)) { var aggregate = repo.Aggregate; if (!createIfNotExists && aggregate.Version == 0) { throw new UninitializedAggregateException(); } CheckAggregateVersionForIfVersionEqualTo(repo.Aggregate); //TODO: Waiting is not a perfect solution, but we cannot await inside a lock. var callbackResult = callback(aggregate).Result; if (!callbackResult.ShouldNotPersistAggregate) { //TODO: Waiting is not a perfect solution, but we cannot await inside a lock. repo.SaveAsync(_commitId, StoreCommandHeaders).Wait(); } } } } else { //This is the classic command execution, each execution reload the entity and stream. var aggregate = await Repository.GetByIdAsync <TAggregate>(id).ConfigureAwait(false); if (!createIfNotExists && aggregate.Version == 0) { throw new UninitializedAggregateException(); } CheckAggregateVersionForIfVersionEqualTo(aggregate); var callbackResult = await callback(aggregate).ConfigureAwait(false); if (!callbackResult.ShouldNotPersistAggregate) { await Repository.SaveAsync(aggregate, _commitId.ToString(), StoreCommandHeaders).ConfigureAwait(false); } } }