Skip to content

Commit c7aaf08

Browse files
committed
- changes made for DocumentDb
1 parent 92d3a4c commit c7aaf08

14 files changed

Lines changed: 560 additions & 56 deletions
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<configuration>
3+
<appSettings>
4+
<!-- Replace the value with the value you copied from the Azure management portal -->
5+
<add key="EndPointUrl" value="https://example.com:443/"/>
6+
<!-- Replace the value with the value you copied from the Azure management portal -->
7+
<add key="AuthorizationKey" value="DocumentDBSample"/>
8+
<add key="DatabaseId" value="Entertainment"/>
9+
<add key="CollectionId" value="Games"/>
10+
</appSettings>
11+
</configuration>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
using System.Configuration;
3+
using SharpRepository.Repository;
4+
using SharpRepository.Repository.Configuration;
5+
6+
namespace SharpRepository.AzureDocumentDb
7+
{
8+
public class DocumentDbConfigRepositoryFactory : ConfigRepositoryFactory
9+
{
10+
public DocumentDbConfigRepositoryFactory(IRepositoryConfiguration config)
11+
: base(config)
12+
{
13+
}
14+
15+
public override IRepository<T> GetInstance<T>()
16+
{
17+
throw new NotImplementedException("DocumentDbRepository does not support using IRepository<T> directly to reference a IRepository<T, string>");
18+
}
19+
20+
public override IRepository<T, TKey> GetInstance<T, TKey>()
21+
{
22+
if (typeof(TKey) != typeof(string))
23+
throw new NotImplementedException(string.Format("DocumentDbRepository does not support using {0} as a Key. {1} only supported as a Key.", typeof(TKey), typeof(string)));
24+
25+
// check for required parameters
26+
if (String.IsNullOrEmpty(RepositoryConfiguration["endpointUrl"])
27+
&& String.IsNullOrEmpty(RepositoryConfiguration["authorizationKey"])
28+
&& String.IsNullOrEmpty(RepositoryConfiguration["databaseId"]))
29+
{
30+
throw new ConfigurationErrorsException("The endpointUrl, authorizationKey, databaseId attribute is required in order to use the MongoDbRepository via the configuration file.");
31+
}
32+
33+
var createIfNotExists = false;
34+
Boolean.TryParse(RepositoryConfiguration["createIfNotExists"], out createIfNotExists);
35+
36+
return new DocumentDbRepository<T, TKey>(RepositoryConfiguration["endpointUrl"], RepositoryConfiguration["authorizationKey"], RepositoryConfiguration["databaseId"], createIfNotExists);
37+
}
38+
39+
public override ICompoundKeyRepository<T, TKey, TKey2> GetInstance<T, TKey, TKey2>()
40+
{
41+
throw new NotImplementedException();
42+
}
43+
}
44+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using Microsoft.Azure.Documents;
2+
using SharpRepository.Repository.Caching;
3+
4+
namespace SharpRepository.AzureDocumentDb
5+
{
6+
public class DocumentDbRepository<T, TKey> : DocumentDbRepositoryBase<T, TKey> where T : class, new()
7+
{
8+
public DocumentDbRepository(string endpointUrl, string authorizationKey, string databaseId, bool createIfNotExists, ICachingStrategy<T, TKey> cachingStrategy = null)
9+
: base(endpointUrl, authorizationKey, databaseId, createIfNotExists, cachingStrategy)
10+
{
11+
}
12+
}
13+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
using System;
2+
using System.Linq;
3+
using System.Linq.Expressions;
4+
using System.Reflection;
5+
using System.Text.RegularExpressions;
6+
using System.Threading.Tasks;
7+
using Microsoft.Azure.Documents;
8+
using Microsoft.Azure.Documents.Client;
9+
using Microsoft.Azure.Documents.Linq;
10+
using Newtonsoft.Json;
11+
using Nito.AsyncEx.Synchronous;
12+
using SharpRepository.Repository;
13+
using SharpRepository.Repository.Caching;
14+
using SharpRepository.Repository.FetchStrategies;
15+
using SharpRepository.Repository.Helpers;
16+
using SharpRepository.Repository.Specifications;
17+
18+
namespace SharpRepository.AzureDocumentDb
19+
{
20+
public class DocumentDbRepositoryBase<T, TKey> : LinqRepositoryBase<T, TKey> where T : class, new()
21+
{
22+
protected DocumentClient Client { get; set; }
23+
protected Database Database { get; set; }
24+
protected DocumentCollection BaseCollection { get; set; }
25+
protected string CollectionId { get; set; }
26+
27+
internal DocumentDbRepositoryBase(string endpointUrl, string authorizationKey, string databaseId, bool createIfNotExists, ICachingStrategy<T, TKey> cachingStrategy = null)
28+
: base(cachingStrategy)
29+
{
30+
Client = new DocumentClient(new Uri(endpointUrl), authorizationKey);
31+
32+
Initilize(databaseId, createIfNotExists);
33+
}
34+
35+
private void Initilize(string databaseId, bool createIfNotExists)
36+
{
37+
Database = Client.CreateDatabaseQuery().Where(db => db.Id == databaseId).AsEnumerable().FirstOrDefault();
38+
39+
if (Database == null && createIfNotExists)
40+
Database = DocumentDbRepositoryManager.CreateDatabase(Client, databaseId).WaitAndUnwrapException();
41+
42+
if (Database == null)
43+
throw new Exception(string.Format("No database {0} existed. Use createIfNotExists = true in order to create database.", databaseId));
44+
45+
Regex rgx = new Regex("[^a-zA-Z0-9 -]");
46+
CollectionId = rgx.Replace(typeof(T).FullName, "");
47+
48+
BaseCollection =
49+
Client.CreateDocumentCollectionQuery(Database.SelfLink)
50+
.Where(c => c.Id == CollectionId)
51+
.ToArray()
52+
.FirstOrDefault() ??
53+
DocumentDbRepositoryManager.CreateCollection(Client, Database, CollectionId).WaitAndUnwrapException();
54+
}
55+
56+
protected override Specification<T> CreateSpecification(Expression<Func<T, bool>> lambda)
57+
{
58+
return new DocumentDbSpecification<T>(lambda);
59+
}
60+
61+
protected override IQueryable<T> BaseQuery(IFetchStrategy<T> fetchStrategy = null)
62+
{
63+
return Client.CreateDocumentQuery<T>(BaseCollection.DocumentsLink).AsQueryable();
64+
}
65+
66+
protected virtual string GetSelfLink(TKey id)
67+
{
68+
var propInfo = GetPrimaryKeyPropertyInfo();
69+
70+
var parameter = Expression.Parameter(typeof(T), "x");
71+
var lambda = Expression.Lambda<Func<T, bool>>(
72+
Expression.Equal(
73+
Expression.PropertyOrField(parameter, propInfo.Name),
74+
Expression.Constant(id)
75+
),
76+
parameter
77+
);
78+
79+
var query = Client.CreateDocumentQuery<Document>(BaseCollection.DocumentsLink, string.Format("SELECT * FROM {0} e WHERE e.{1}", CollectionId, lambda.ToMSSqlString()));
80+
81+
var doc = query.AsEnumerable().FirstOrDefault();
82+
83+
if (doc != null)
84+
return doc.SelfLink;
85+
86+
return null;
87+
}
88+
89+
protected override void AddItem(T entity)
90+
{
91+
Client.CreateDocumentAsync(BaseCollection.DocumentsLink, entity).WaitAndUnwrapException();
92+
}
93+
94+
protected override void DeleteItem(T entity)
95+
{
96+
TKey id;
97+
if (!GetPrimaryKey(entity, out id))
98+
return;
99+
100+
var selfLink = GetSelfLink(id);
101+
102+
Client.DeleteDocumentAsync(selfLink).WaitAndUnwrapException();
103+
}
104+
105+
protected override void UpdateItem(T entity)
106+
{
107+
TKey id;
108+
if (!GetPrimaryKey(entity, out id))
109+
return;
110+
111+
var selfLink = GetSelfLink(id);
112+
113+
Client.ReplaceDocumentAsync(selfLink, entity).WaitAndUnwrapException();
114+
}
115+
116+
protected override PropertyInfo GetPrimaryKeyPropertyInfo()
117+
{
118+
// checks for the MongoDb BsonIdAttribute and if not there no the normal checks
119+
var type = typeof(T);
120+
121+
return type.GetProperties().FirstOrDefault(x => x.HasAttribute<JsonPropertyAttribute>() && x.GetCustomAttribute<JsonPropertyAttribute>().PropertyName.ToLower() == "id" && x.PropertyType == typeof(string))
122+
?? base.GetPrimaryKeyPropertyInfo();
123+
}
124+
125+
protected override void SaveChanges()
126+
{
127+
}
128+
129+
public override void Dispose()
130+
{
131+
Client.Dispose();
132+
}
133+
}
134+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using SharpRepository.Repository.Configuration;
2+
3+
namespace SharpRepository.AzureDocumentDb
4+
{
5+
public class DocumentDbRepositoryConfiguration : RepositoryConfiguration
6+
{
7+
public DocumentDbRepositoryConfiguration(string endpointUrl, string authorizationKey, string databaseId, bool createIfNotExists = false, string cachingStrategy = null, string cachingProvider = null)
8+
{
9+
EndpointUrl = endpointUrl;
10+
AuthorizationKey = authorizationKey;
11+
DatabaseId = databaseId;
12+
CreateIfNotExists = createIfNotExists;
13+
14+
CachingProvider = cachingProvider;
15+
CachingStrategy = cachingStrategy;
16+
Factory = typeof(DocumentDbConfigRepositoryFactory);
17+
}
18+
19+
public string EndpointUrl
20+
{
21+
set { Attributes["endpointUrl"] = value; }
22+
}
23+
24+
public string AuthorizationKey
25+
{
26+
set { Attributes["authorizationKey"] = value; }
27+
}
28+
29+
public string DatabaseId
30+
{
31+
set { Attributes["databaseId"] = value; }
32+
}
33+
34+
public bool CreateIfNotExists
35+
{
36+
set { Attributes["createIfNotExists"] = value.ToString(); }
37+
}
38+
39+
}
40+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System.Threading.Tasks;
2+
using Microsoft.Azure.Documents;
3+
using Microsoft.Azure.Documents.Client;
4+
5+
namespace SharpRepository.AzureDocumentDb
6+
{
7+
public static class DocumentDbRepositoryManager
8+
{
9+
public async static Task<Database> CreateDatabase(DocumentClient client, string databaseId)
10+
{
11+
return await client.CreateDatabaseAsync(new Database { Id = databaseId });
12+
}
13+
14+
public async static Task<DocumentCollection> CreateCollection(DocumentClient client, Database database, string collectionId)
15+
{
16+
return await client.CreateDocumentCollectionAsync(database.SelfLink, new DocumentCollection { Id = collectionId });
17+
}
18+
19+
public async static void DropDatabase(DocumentClient client, Database database)
20+
{
21+
await client.DeleteDatabaseAsync(database.SelfLink);
22+
}
23+
}
24+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System;
2+
using System.Linq;
3+
using System.Linq.Expressions;
4+
using SharpRepository.Repository.FetchStrategies;
5+
using SharpRepository.Repository.Specifications;
6+
7+
namespace SharpRepository.AzureDocumentDb
8+
{
9+
public class DocumentDbSpecification<T> : Specification<T>
10+
{
11+
public DocumentDbSpecification()
12+
: base((Expression<Func<T, bool>>)null)
13+
{
14+
// null Predicate means it matches everything
15+
}
16+
17+
public DocumentDbSpecification(Expression<Func<T, bool>> predicate)
18+
: base(predicate)
19+
{
20+
}
21+
22+
public DocumentDbSpecification(ISpecification<T> specification)
23+
: base(specification)
24+
{
25+
}
26+
27+
public override T SatisfyingEntityFrom(IQueryable<T> query)
28+
{
29+
return SatisfyingEntitiesFrom(query).AsEnumerable().FirstOrDefault();
30+
}
31+
}
32+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System;
2+
using System.Linq.Expressions;
3+
using System.Reflection;
4+
using Newtonsoft.Json;
5+
using SharpRepository.Repository.Helpers;
6+
7+
namespace SharpRepository.AzureDocumentDb
8+
{
9+
public static class ExpressionExtensions
10+
{
11+
public static string ToMSSqlString(this Expression expression)
12+
{
13+
switch (expression.NodeType)
14+
{
15+
case ExpressionType.Add:
16+
var add = expression as BinaryExpression;
17+
return add.Left.ToMSSqlString() + " + " + add.Right.ToMSSqlString();
18+
19+
case ExpressionType.Constant:
20+
var constant = expression as ConstantExpression;
21+
if (constant.Type == typeof(string))
22+
return "'" + constant.Value.ToString().Replace("'", "''") + "'";
23+
return constant.Value.ToString();
24+
25+
case ExpressionType.Equal:
26+
var equal = expression as BinaryExpression;
27+
return equal.Left.ToMSSqlString() + " = " +
28+
equal.Right.ToMSSqlString();
29+
30+
case ExpressionType.Lambda:
31+
var lambda = expression as LambdaExpression;
32+
return lambda.Body.ToMSSqlString();
33+
34+
case ExpressionType.MemberAccess:
35+
var memberaccess = expression as MemberExpression;
36+
37+
return GetJsonPropNameAttribute(memberaccess.Member) ?? memberaccess.Member.Name;
38+
}
39+
40+
throw new NotImplementedException(
41+
expression.GetType() + " " +
42+
expression.NodeType);
43+
}
44+
45+
private static string GetJsonPropNameAttribute(MemberInfo memberInfo)
46+
{
47+
var jsonProp = memberInfo.GetOneAttribute<JsonPropertyAttribute>();
48+
49+
if (jsonProp != null)
50+
return jsonProp.PropertyName;
51+
return null;
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)