/// <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); }
/// <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)); }
/// <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); } } }
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)); }