Line data Source code
1 : #region Copyright
2 : // // -----------------------------------------------------------------------
3 : // // <copyright company="Chinchilla Software Limited">
4 : // // Copyright Chinchilla Software Limited. All rights reserved.
5 : // // </copyright>
6 : // // -----------------------------------------------------------------------
7 : #endregion
8 :
9 : using System;
10 : using System.Collections.Generic;
11 : using Cqrs.Domain.Exceptions;
12 : using Cqrs.Events;
13 :
14 : namespace Cqrs.Domain
15 : {
16 : /// <summary>
17 : /// Provides a basic container to control when <see cref="IEvent{TAuthenticationToken}">events</see> are store in an <see cref="IEventStore{TAuthenticationToken}"/> and then published on an <see cref="IEventPublisher{TAuthenticationToken}"/>.
18 : /// </summary>
19 : /// <remarks>
20 : /// This shouldn't normally be used as a singleton.
21 : /// </remarks>
22 : public class UnitOfWork<TAuthenticationToken>
23 : : IUnitOfWork<TAuthenticationToken>
24 1 : {
25 : private IAggregateRepository<TAuthenticationToken> Repository { get; set; }
26 :
27 : private ISnapshotAggregateRepository<TAuthenticationToken> SnapshotRepository { get; set; }
28 :
29 : private Dictionary<Guid, IAggregateDescriptor<TAuthenticationToken>> TrackedAggregates { get; set; }
30 :
31 : /// <summary>
32 : /// Instantiates a new instance of <see cref="UnitOfWork{TAuthenticationToken}"/>
33 : /// </summary>
34 1 : public UnitOfWork(ISnapshotAggregateRepository<TAuthenticationToken> snapshotRepository, IAggregateRepository<TAuthenticationToken> repository)
35 : : this(repository)
36 : {
37 : if (snapshotRepository == null)
38 : throw new ArgumentNullException("snapshotRepository");
39 :
40 : SnapshotRepository = snapshotRepository;
41 : }
42 :
43 : /// <summary>
44 : /// Instantiates a new instance of <see cref="UnitOfWork{TAuthenticationToken}"/>
45 : /// </summary>
46 1 : public UnitOfWork(IAggregateRepository<TAuthenticationToken> repository)
47 : {
48 : if(repository == null)
49 : throw new ArgumentNullException("repository");
50 :
51 : Repository = repository;
52 : TrackedAggregates = new Dictionary<Guid, IAggregateDescriptor<TAuthenticationToken>>();
53 : }
54 :
55 : /// <summary>
56 : /// Add an item into the <see cref="IUnitOfWork{TAuthenticationToken}"/> ready to be committed.
57 : /// </summary>
58 1 : public virtual void Add<TAggregateRoot>(TAggregateRoot aggregate, bool useSnapshots = false)
59 : where TAggregateRoot : IAggregateRoot<TAuthenticationToken>
60 : {
61 : if (!IsTracked(aggregate.Id))
62 : {
63 : var aggregateDescriptor = new AggregateDescriptor<TAggregateRoot, TAuthenticationToken>
64 : {
65 : Aggregate = aggregate,
66 : Version = aggregate.Version,
67 : UseSnapshots = useSnapshots
68 : };
69 : TrackedAggregates.Add(aggregate.Id, aggregateDescriptor);
70 : }
71 : else if (((TrackedAggregates[aggregate.Id]).Aggregate) != (IAggregateRoot<TAuthenticationToken>)aggregate)
72 : throw new ConcurrencyException(aggregate.Id);
73 : }
74 :
75 : /// <summary>
76 : /// Get an item from the <see cref="IUnitOfWork{TAuthenticationToken}"/> if it has already been loaded or get it from the <see cref="IAggregateRepository{TAuthenticationToken}"/>.
77 : /// </summary>
78 1 : public virtual TAggregateRoot Get<TAggregateRoot>(Guid id, int? expectedVersion = null, bool useSnapshots = false)
79 : where TAggregateRoot : IAggregateRoot<TAuthenticationToken>
80 : {
81 : if(IsTracked(id))
82 : {
83 : var trackedAggregate = (TAggregateRoot)TrackedAggregates[id].Aggregate;
84 : if (expectedVersion != null && trackedAggregate.Version != expectedVersion)
85 : throw new ConcurrencyException(trackedAggregate.Id);
86 : return trackedAggregate;
87 : }
88 :
89 : var aggregate = (useSnapshots ? SnapshotRepository : Repository).Get<TAggregateRoot>(id);
90 : if (expectedVersion != null && aggregate.Version != expectedVersion)
91 : throw new ConcurrencyException(id);
92 : Add(aggregate, useSnapshots);
93 :
94 : return aggregate;
95 : }
96 :
97 : /// <summary>
98 : /// Get an item from the <see cref="IUnitOfWork{TAuthenticationToken}"/> up to and including the provided <paramref name="version"/>.
99 : /// </summary>
100 : /// <typeparam name="TAggregateRoot">The <see cref="Type"/> of the <see cref="IAggregateRoot{TAuthenticationToken}"/> the <see cref="IEvent{TAuthenticationToken}"/> was raised in.</typeparam>
101 : /// <param name="id">The <see cref="IAggregateRoot{TAuthenticationToken}.Id"/> of the <see cref="IAggregateRoot{TAuthenticationToken}"/>.</param>
102 : /// <param name="version">Load events up-to and including from this version</param>
103 1 : public virtual TAggregateRoot GetToVersion<TAggregateRoot>(Guid id, int version)
104 : where TAggregateRoot : IAggregateRoot<TAuthenticationToken>
105 : {
106 : var aggregate = Repository.GetToVersion<TAggregateRoot>(id, version);
107 :
108 : return aggregate;
109 : }
110 :
111 : /// <summary>
112 : /// Get an item from the <see cref="IUnitOfWork{TAuthenticationToken}"/> up to and including the provided <paramref name="versionedDate"/>.
113 : /// </summary>
114 : /// <typeparam name="TAggregateRoot">The <see cref="Type"/> of the <see cref="IAggregateRoot{TAuthenticationToken}"/> the <see cref="IEvent{TAuthenticationToken}"/> was raised in.</typeparam>
115 : /// <param name="id">The <see cref="IAggregateRoot{TAuthenticationToken}.Id"/> of the <see cref="IAggregateRoot{TAuthenticationToken}"/>.</param>
116 : /// <param name="versionedDate">Load events up-to and including from this <see cref="DateTime"/></param>
117 1 : public virtual TAggregateRoot GetToDate<TAggregateRoot>(Guid id, DateTime versionedDate)
118 : where TAggregateRoot : IAggregateRoot<TAuthenticationToken>
119 : {
120 : var aggregate = Repository.GetToDate<TAggregateRoot>(id, versionedDate);
121 :
122 : return aggregate;
123 : }
124 :
125 : private bool IsTracked(Guid id)
126 : {
127 : return TrackedAggregates.ContainsKey(id);
128 : }
129 :
130 : /// <summary>
131 : /// Commit any changed <see cref="AggregateRoot{TAuthenticationToken}"/> added to this <see cref="IUnitOfWork{TAuthenticationToken}"/> via <see cref="Add{T}"/>
132 : /// into the <see cref="IAggregateRepository{TAuthenticationToken}"/>
133 : /// </summary>
134 1 : public virtual void Commit()
135 : {
136 : foreach (IAggregateDescriptor<TAuthenticationToken> descriptor in TrackedAggregates.Values)
137 : {
138 : (descriptor.UseSnapshots ? SnapshotRepository : Repository).Save(descriptor.Aggregate, descriptor.Version);
139 : }
140 : TrackedAggregates.Clear();
141 : }
142 : }
143 : }
|