/// <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);
     }
 }
        public void convert_to_identity()
        {
            var asString = EventStoreIdentity.Format(typeof(SampleAggregateId), 1L);
            var identity = (EventStoreIdentity)_manager.ToIdentity(asString);

            Assert.IsTrue(identity is SampleAggregateId);
            Assert.AreEqual("SampleAggregate", identity.GetTag());
            Assert.AreEqual(1L, identity.Id);
        }
 protected void FindAndModify(EventStoreIdentity id, Action<TAggregate> callback, bool createIfNotExists = false)
 {
     var aggregate = Repository.GetById<TAggregate>(id);
     if (!createIfNotExists && aggregate.Version == 0)
         throw new UninitializedAggregateException();
     SetupContext(aggregate);
     callback(aggregate);
     Repository.Save(aggregate, _commitId, StoreCommandHeaders);
 }
Пример #4
0
 /// <summary>
 /// To maintain compatibility with the old command handler.
 /// </summary>
 /// <param name="id"></param>
 /// <param name="callback"></param>
 /// <param name="createIfNotExists"></param>
 /// <returns></returns>
 protected virtual Task FindAndModifyAsync(
     EventStoreIdentity id,
     Action <TAggregate> callback,
     bool createIfNotExists = false)
 {
     return(FindAndModifyAsync(id, a =>
     {
         callback(a);
         return Task.FromResult(RepositoryCommandHandlerCallbackReturnValue.Default);
     },
                               createIfNotExists));
 }
Пример #5
0
        /// <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);
                }
            }
        }
Пример #6
0
        public Type GetAggregateFromId(EventStoreIdentity identity)
        {
            Type type;

            if (_associationCache.TryGetValue(identity.GetType(), out type))
            {
                return(type);
            }

            var tag = identity.GetTag();
            var namespaceFirstPart = identity.GetType().Namespace.Split('.').First();
            var aggregate          = _aggregateRoots
                                     .Where(_ => _.Namespace.StartsWith(namespaceFirstPart + ".") &&
                                            _.Name.Equals(tag, StringComparison.OrdinalIgnoreCase))
                                     .ToList();

            if (aggregate.Count > 1)
            {
                Logger.ErrorFormat("Unable to find related aggregate for id {0}, we have multiple aggregate with naming convention {1}", identity.GetType().FullName, String.Join(",", aggregate.Select(_ => _.FullName)));
                throw new JarvisFrameworkEngineException($"Unable to find related aggregate for id {identity.GetType().FullName}, we have multiple aggregate with naming convention {aggregate.Select(_ => _.FullName)}");
            }

            return(aggregate.FirstOrDefault());
        }
 public void Successful_detect_wrong_identities(String id)
 {
     Assert.That(EventStoreIdentity.Match <SampleAggregateId>(id), Is.False);
 }
 public void Successful_match_correct_identities(String id)
 {
     Assert.That(EventStoreIdentity.Match <SampleAggregateId>(id));
 }