/// <summary> /// Save the specified <paramref name="context"/> changes for the given aggregate. /// </summary> /// <param name="aggregate">The current aggregate version for which the context applies.</param> /// <param name="context">The command context containing the aggregate changes to be applied.</param> public SaveResult Save(Aggregate aggregate, CommandContext context) { Verify.NotNull(aggregate, nameof(aggregate)); Verify.NotNull(context, nameof(context)); var copy = aggregate.Copy(); var aggregateType = aggregate.GetType(); var key = String.Concat(aggregateType.GetFullNameWithAssembly(), "-", aggregate.Id); using (var aggregateLock = new AggregateLock(aggregateType, aggregate.Id)) { aggregateLock.Aquire(); try { var result = aggregateStore.Save(copy, context); memoryCache.Set(key, copy, CreateCacheItemPolicy()); return(result); } catch (ConcurrencyException) { memoryCache.Remove(key); throw; } } }
/// <summary> /// Retrieve the aggregate of the specified <paramref name="aggregateType"/> and aggregate <paramref name="id"/>. /// </summary> /// <param name="aggregateType">The type of aggregate to retrieve.</param> /// <param name="id">The unique aggregate id.</param> public Aggregate Get(Type aggregateType, Guid id) { Verify.NotNull(aggregateType, nameof(aggregateType)); var key = String.Concat(aggregateType.GetFullNameWithAssembly(), "-", id); using (var aggregateLock = new AggregateLock(aggregateType, id)) { aggregateLock.Aquire(); //NOTE: We do not want to use AddOrGetExisting due to internal global cache lock while doing aggregate lookup. var aggregate = (Aggregate)memoryCache.Get(key); if (aggregate == null) { memoryCache.Add(key, aggregate = aggregateStore.Get(aggregateType, id), CreateCacheItemPolicy()); } //NOTE: Given that aggregate state is only applied during `Save`, we can return the cached instance. // This avoids making a copy of the aggregate when no state changes will be applied. return(aggregate); } }
/// <summary> /// Retrieve the aggregate of the specified <paramref name="aggregateType"/> and aggregate <paramref name="id"/>. /// </summary> /// <param name="aggregateType">The type of aggregate to retrieve.</param> /// <param name="id">The unique aggregate id.</param> public Aggregate Get(Type aggregateType, Guid id) { Verify.NotNull(aggregateType, nameof(aggregateType)); var key = String.Concat(aggregateType.GetFullNameWithAssembly(), "-", id); using (var aggregateLock = new AggregateLock(aggregateType, id)) { aggregateLock.Aquire(); //NOTE: We do not want to use AddOrGetExisting due to internal global cache lock while doing aggregate lookup. var aggregate = (Aggregate)memoryCache.Get(key); if (aggregate == null) memoryCache.Add(key, aggregate = aggregateStore.Get(aggregateType, id), CreateCacheItemPolicy()); //NOTE: Given that aggregate state is only applied during `Save`, we can return the cached instance. // This avoids making a copy of the aggregate when no state changes will be applied. return aggregate; } }
/// <summary> /// Save the specified <paramref name="context"/> changes for the given aggregate. /// </summary> /// <param name="aggregate">The current aggregate version for which the context applies.</param> /// <param name="context">The command context containing the aggregate changes to be applied.</param> public SaveResult Save(Aggregate aggregate, CommandContext context) { Verify.NotNull(aggregate, nameof(aggregate)); Verify.NotNull(context, nameof(context)); var copy = aggregate.Copy(); var aggregateType = aggregate.GetType(); var key = String.Concat(aggregateType.GetFullNameWithAssembly(), "-", aggregate.Id); using (var aggregateLock = new AggregateLock(aggregateType, aggregate.Id)) { aggregateLock.Aquire(); try { var result = aggregateStore.Save(copy, context); memoryCache.Set(key, copy, CreateCacheItemPolicy()); return result; } catch (ConcurrencyException) { memoryCache.Remove(key); throw; } } }