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;
11 : using System.Collections.Generic;
12 : using System.Linq;
13 : using System.Linq.Expressions;
14 : using Cqrs.Azure.DocumentDb.Entities;
15 : using Cqrs.DataStores;
16 : using cdmdotnet.Logging;
17 : using Cqrs.Entities;
18 : using Microsoft.Azure.Documents;
19 : using Microsoft.Azure.Documents.Client;
20 : using Microsoft.Azure.Documents.Linq;
21 :
22 : namespace Cqrs.Azure.DocumentDb.DataStores
23 : {
24 : /// <summary>
25 : /// A <see cref="IDataStore{TData}"/> that uses Azure DocumentDB (CosmosDB) for storage.
26 : /// </summary>
27 : /// <typeparam name="TData">The <see cref="Type"/> of <see cref="IEntity"/> the <see cref="IDataStore{TData}"/> will contain.</typeparam>
28 : public class AzureDocumentDbDataStore<TData> : IDataStore<TData>
29 : where TData : AzureDocumentDbEntity
30 1 : {
31 : /// <summary>
32 : /// Gets or sets the <see cref="DocumentClient"/>
33 : /// </summary>
34 : protected DocumentClient AzureDocumentDbClient { get; private set; }
35 :
36 : /// <summary>
37 : /// Gets or sets the <see cref="Database"/>
38 : /// </summary>
39 : protected Database AzureDocumentDbDatabase { get; private set; }
40 :
41 : /// <summary>
42 : /// Gets or sets the <see cref="DocumentCollection"/>
43 : /// </summary>
44 : protected DocumentCollection AzureDocumentDbCollection { get; private set; }
45 :
46 : /// <summary>
47 : /// Gets or sets the <see cref="IOrderedQueryable{T}"/>
48 : /// </summary>
49 : protected IOrderedQueryable<TData> AzureDocumentDbQuery { get; private set; }
50 :
51 : /// <summary>
52 : /// Gets or sets the <see cref="IAzureDocumentDbHelper"/>
53 : /// </summary>
54 : protected IAzureDocumentDbHelper AzureDocumentDbHelper { get; private set; }
55 :
56 : /// <summary>
57 : /// Gets or sets the <see cref="ILogger"/>
58 : /// </summary>
59 : protected ILogger Logger { get; private set; }
60 :
61 : /// <summary>
62 : /// Instantiates and Initialises a new instance of the <see cref="AzureDocumentDbDataStore{TData}"/> class.
63 : /// </summary>
64 1 : public AzureDocumentDbDataStore(ILogger logger, DocumentClient azureDocumentDbClient, Database azureDocumentDbDatabase, DocumentCollection azureDocumentDbCollection, IOrderedQueryable<TData> azureDocumentDbQuery, IAzureDocumentDbHelper azureDocumentDbHelper)
65 : {
66 : Logger = logger;
67 : AzureDocumentDbClient = azureDocumentDbClient;
68 : AzureDocumentDbDatabase = azureDocumentDbDatabase;
69 : AzureDocumentDbCollection = azureDocumentDbCollection;
70 : AzureDocumentDbQuery = azureDocumentDbQuery;
71 : AzureDocumentDbHelper = azureDocumentDbHelper;
72 : }
73 :
74 : #region Implementation of IEnumerable
75 :
76 : /// <summary>
77 : /// Returns an enumerator that iterates through the collection.
78 : /// </summary>
79 : /// <returns>
80 : /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
81 : /// </returns>
82 : /// <filterpriority>1</filterpriority>
83 1 : public IEnumerator<TData> GetEnumerator()
84 : {
85 : Logger.LogDebug("Getting the enumerator for an Azure database query", "AzureDocumentDbDataStore\\GetEnumerator");
86 : try
87 : {
88 : DateTime start = DateTime.Now;
89 : IEnumerator<TData> result = AzureDocumentDbHelper.ExecuteFaultTollerantFunction(() => AzureDocumentDbQuery.GetEnumerator());
90 : DateTime end = DateTime.Now;
91 : Logger.LogDebug(string.Format("Getting the enumerator for an Azure database query took {0}", end - start), "AzureDocumentDbDataStore\\GetEnumerator");
92 : return result;
93 : }
94 : finally
95 : {
96 : Logger.LogDebug("Getting the enumerator for an Azure database query... Done", "AzureDocumentDbDataStore\\GetEnumerator");
97 : }
98 : }
99 :
100 : /// <summary>
101 : /// Returns an enumerator that iterates through a collection.
102 : /// </summary>
103 : /// <returns>
104 : /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
105 : /// </returns>
106 : /// <filterpriority>2</filterpriority>
107 : IEnumerator IEnumerable.GetEnumerator()
108 : {
109 : return GetEnumerator();
110 : }
111 :
112 : #endregion
113 :
114 : #region Implementation of IQueryable
115 :
116 : /// <summary>
117 : /// Gets the expression tree that is associated with the instance of <see cref="T:System.Linq.IQueryable"/>.
118 : /// </summary>
119 : /// <returns>
120 : /// The <see cref="T:System.Linq.Expressions.Expression"/> that is associated with this instance of <see cref="T:System.Linq.IQueryable"/>.
121 : /// </returns>
122 : public Expression Expression
123 : {
124 : get { return AzureDocumentDbQuery.Expression; }
125 : }
126 :
127 : /// <summary>
128 : /// Gets the type of the element(s) that are returned when the expression tree associated with this instance of <see cref="T:System.Linq.IQueryable"/> is executed.
129 : /// </summary>
130 : /// <returns>
131 : /// A <see cref="T:System.Type"/> that represents the type of the element(s) that are returned when the expression tree associated with this object is executed.
132 : /// </returns>
133 : public Type ElementType
134 : {
135 : get { return AzureDocumentDbQuery.ElementType; }
136 : }
137 :
138 : /// <summary>
139 : /// Gets the singleResultQuery provider that is associated with this data source.
140 : /// </summary>
141 : /// <returns>
142 : /// The <see cref="T:System.Linq.IQueryProvider"/> that is associated with this data source.
143 : /// </returns>
144 : public IQueryProvider Provider
145 : {
146 : get { return AzureDocumentDbQuery.Provider; }
147 : }
148 :
149 : #endregion
150 :
151 : #region Implementation of IDataStore<TData>
152 :
153 : /// <summary>
154 : /// Add the provided <paramref name="data"/> to the data store and persist the change.
155 : /// </summary>
156 1 : public void Add(TData data)
157 : {
158 : Logger.LogDebug("Adding data to the Azure database", "AzureDocumentDbDataStore\\Add");
159 : try
160 : {
161 : DateTime start = DateTime.Now;
162 : ResourceResponse<Document> result = AzureDocumentDbHelper.ExecuteFaultTollerantFunction(() => AzureDocumentDbClient.CreateDocumentAsync((AzureDocumentDbCollection).SelfLink, data).Result);
163 : DateTime end = DateTime.Now;
164 : Logger.LogDebug(string.Format("Adding data in the Azure database took {0} and cost:r\n{1}", end - start, result), "AzureDocumentDbDataStore\\Add");
165 : }
166 : finally
167 : {
168 : Logger.LogDebug("Adding data to the Azure database... Done", "AzureDocumentDbDataStore\\Add");
169 : }
170 : }
171 :
172 : /// <summary>
173 : /// Add the provided <paramref name="data"/> to the data store and persist the change.
174 : /// </summary>
175 1 : public void Add(IEnumerable<TData> data)
176 : {
177 : Logger.LogDebug("Adding data collection to the Azure database", "AzureDocumentDbDataStore\\Add");
178 : try
179 : {
180 : foreach (TData model in data)
181 : {
182 : Add(model);
183 : }
184 : }
185 : finally
186 : {
187 : Logger.LogDebug("Adding data collection to the Azure database... Done", "AzureDocumentDbDataStore\\Add");
188 : }
189 : }
190 :
191 : /// <summary>
192 : /// Will mark the <paramref name="data"/> as logically (or soft) by setting <see cref="Entity.IsLogicallyDeleted"/> to true
193 : /// </summary>
194 1 : public void Remove(TData data)
195 : {
196 : Logger.LogDebug("Removing data from the Azure database", "AzureDocumentDbDataStore\\Remove");
197 : try
198 : {
199 : data.IsLogicallyDeleted = true;
200 : Update(data);
201 : }
202 : finally
203 : {
204 : Logger.LogDebug("Removing data from the Azure database... Done", "AzureDocumentDbDataStore\\Remove");
205 : }
206 : }
207 :
208 : /// <summary>
209 : /// Remove the provided <paramref name="data"/> (normally by <see cref="IEntity.Rsn"/>) from the data store and persist the change.
210 : /// </summary>
211 1 : public void Destroy(TData data)
212 : {
213 : Logger.LogDebug("Destroying data from the Azure database", "AzureDocumentDbDataStore\\Destroy");
214 : try
215 : {
216 : Logger.LogDebug("Getting existing document from the Azure database", "AzureDocumentDbDataStore\\Destroy");
217 : DateTime start = DateTime.Now;
218 : Document documentToUpdate = AzureDocumentDbClient.CreateDocumentQuery(AzureDocumentDbCollection.DocumentsLink)
219 : .Where(d => d.Id == data.id)
220 : .AsEnumerable()
221 : .Single();
222 : DateTime mid = DateTime.Now;
223 : Logger.LogDebug(string.Format("Getting existing document from the Azure database took {0}", mid - start), "AzureDocumentDbDataStore\\Destroy");
224 : Logger.LogDebug("Destroying existing document in the Azure database", "AzureDocumentDbDataStore\\Destroy");
225 : ResourceResponse<Document> result = AzureDocumentDbHelper.ExecuteFaultTollerantFunction(() => AzureDocumentDbClient.DeleteDocumentAsync(documentToUpdate.SelfLink).Result);
226 : DateTime end = DateTime.Now;
227 : Logger.LogDebug(string.Format("Destroying existing document in the Azure database took {0} and cost:r\n{1}", end - mid, result), "AzureDocumentDbDataStore\\Destroy");
228 : }
229 : finally
230 : {
231 : Logger.LogDebug("Destroying data from the Azure database... Done", "AzureDocumentDbDataStore\\Destroy");
232 : }
233 : }
234 :
235 : /// <summary>
236 : /// Remove all contents (normally by use of a truncate operation) from the data store and persist the change.
237 : /// </summary>
238 1 : public void RemoveAll()
239 : {
240 : Logger.LogDebug("Removing all from the Azure database", "AzureDocumentDbDataStore\\RemoveAll");
241 : try
242 : {
243 : ResourceResponse<DocumentCollection> result = AzureDocumentDbHelper.ExecuteFaultTollerantFunction(() => AzureDocumentDbClient.DeleteDocumentCollectionAsync(AzureDocumentDbCollection.SelfLink, new RequestOptions()).Result);
244 : }
245 : finally
246 : {
247 : Logger.LogDebug("Removing all from the Azure database... Done", "AzureDocumentDbDataStore\\RemoveAll");
248 : }
249 : }
250 :
251 : /// <summary>
252 : /// Update the provided <paramref name="data"/> in the data store and persist the change.
253 : /// </summary>
254 1 : public void Update(TData data)
255 : {
256 : Logger.LogDebug("Updating data in the Azure database", "AzureDocumentDbDataStore\\Update");
257 : try
258 : {
259 : Logger.LogDebug("Getting existing document from the Azure database", "AzureDocumentDbDataStore\\Update");
260 : DateTime start = DateTime.Now;
261 : Document documentToUpdate = AzureDocumentDbClient.CreateDocumentQuery(AzureDocumentDbCollection.DocumentsLink)
262 : .Where(d => d.Id == data.id)
263 : .AsEnumerable()
264 : .Single();
265 : DateTime mid = DateTime.Now;
266 : Logger.LogDebug(string.Format("Getting existing document from the Azure database took {0}", mid - start), "AzureDocumentDbDataStore\\Update");
267 : Logger.LogDebug("Replacing existing document in the Azure database", "AzureDocumentDbDataStore\\Update");
268 : ResourceResponse<Document> result = AzureDocumentDbHelper.ExecuteFaultTollerantFunction(() => AzureDocumentDbClient.ReplaceDocumentAsync(documentToUpdate.SelfLink, data).Result);
269 : DateTime end = DateTime.Now;
270 : Logger.LogDebug(string.Format("Replacing existing document in the Azure database took {0} and cost:r\n{1}", end - mid, result), "AzureDocumentDbDataStore\\Update");
271 : }
272 : finally
273 : {
274 : Logger.LogDebug("Updating data in the Azure database... Done", "AzureDocumentDbDataStore\\Update");
275 : }
276 : }
277 :
278 : #endregion
279 :
280 : #region Implementation of IDisposable
281 :
282 : /// <summary>
283 : /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
284 : /// </summary>
285 1 : public void Dispose()
286 : {
287 : AzureDocumentDbClient.Dispose();
288 : }
289 :
290 : #endregion
291 :
292 : /// <summary>
293 : /// Returns the instance as an <see cref="IEnumerable{T}"/>.
294 : /// </summary>
295 : /// <returns></returns>
296 1 : public IEnumerable<TData> AsEnumerable()
297 : {
298 : return AzureDocumentDbQuery.AsEnumerable();
299 : }
300 : }
301 : }
|