Skip to content

Commit d38649f

Browse files
(GH-659) Cleaned up in-memory context code
1 parent e777b52 commit d38649f

File tree

4 files changed

+86
-291
lines changed

4 files changed

+86
-291
lines changed

src/DotNetToolkit.Repository.InMemory/Internal/InMemoryDatabase.cs

Lines changed: 26 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -23,75 +23,56 @@ private InMemoryDatabase()
2323

2424
#endregion
2525

26-
#region Public Methods
27-
28-
public static InMemoryDatabase Empty()
29-
{
30-
return new InMemoryDatabase();
31-
}
26+
#region Private Methods
3227

33-
public void Clear()
28+
private static object CombinePrimaryKeyValues(object[] keyValues)
3429
{
35-
_store.Clear();
30+
return keyValues.Length == 1 ? keyValues[0] : string.Join(":", keyValues);
3631
}
3732

38-
public void Clear(Type entityType)
39-
{
40-
Guard.NotNull(entityType, nameof(entityType));
33+
#endregion
4134

42-
var context = GetContext(entityType);
43-
context.Clear();
44-
}
35+
#region Public Methods
4536

46-
public bool Contains(Type entityType, object key)
37+
public static InMemoryDatabase Empty()
4738
{
48-
Guard.NotNull(entityType, nameof(entityType));
49-
Guard.NotNull(key, nameof(key));
50-
51-
return GetContext(entityType).ContainsKey(key);
39+
return new InMemoryDatabase();
5240
}
5341

54-
public bool Contains(Type entityType)
42+
public void Clear()
5543
{
56-
Guard.NotNull(entityType, nameof(entityType));
57-
58-
return GetContext(entityType).Count > 0;
44+
_store.Clear();
5945
}
6046

61-
public void AddOrUpdate(Type entityType, object entity, object key)
47+
public void AddOrUpdate<T>(T entity, object[] keyValues)
6248
{
63-
Guard.NotNull(entityType, nameof(entityType));
6449
Guard.NotNull(entity, nameof(entity));
50+
Guard.NotEmpty(keyValues, nameof(keyValues));
6551

52+
var entityType = typeof(T);
53+
var key = CombinePrimaryKeyValues(keyValues);
6654
var context = GetContext(entityType);
6755

6856
context[key] = Clone(entity);
6957
}
7058

71-
public bool Remove(Type entityType, object key)
59+
public bool Remove<T>(object[] keyValues)
7260
{
73-
Guard.NotNull(entityType, nameof(entityType));
74-
Guard.NotNull(key, nameof(key));
61+
Guard.NotEmpty(keyValues, nameof(keyValues));
7562

63+
var entityType = typeof(T);
64+
var key = CombinePrimaryKeyValues(keyValues);
7665
var context = GetContext(entityType);
7766

7867
return context.TryRemove(key, out _);
7968
}
8069

81-
public object GetLastKey(Type entityType)
82-
{
83-
Guard.NotNull(entityType, nameof(entityType));
84-
85-
var context = GetContext(entityType);
86-
87-
return context.Keys.LastOrDefault();
88-
}
89-
90-
public bool TryFind(Type entityType, object key, out object entity)
70+
public bool TryFind<T>(object[] keyValues, out object entity)
9171
{
92-
Guard.NotNull(entityType, nameof(entityType));
93-
Guard.NotNull(key, nameof(key));
72+
Guard.NotEmpty(keyValues, nameof(keyValues));
9473

74+
var entityType = typeof(T);
75+
var key = CombinePrimaryKeyValues(keyValues);
9576
var context = GetContext(entityType);
9677

9778
if (context.TryGetValue(key, out object obj))
@@ -116,6 +97,11 @@ public IEnumerable<object> FindAll(Type entityType)
11697
}
11798
}
11899

100+
public IEnumerable<T> FindAll<T>()
101+
{
102+
return FindAll(typeof(T)).Cast<T>();
103+
}
104+
119105
#endregion
120106

121107
#region Private Methods

src/DotNetToolkit.Repository.InMemory/Internal/InMemoryDatabaseStoreCache.cs renamed to src/DotNetToolkit.Repository.InMemory/Internal/InMemoryDatabasesCache.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,19 @@
33
using System.Collections.Concurrent;
44
using Utility;
55

6-
internal class InMemoryDatabaseStoreCache
6+
internal class InMemoryDatabasesCache
77
{
88
#region Fields
99

10-
private static volatile InMemoryDatabaseStoreCache _instance;
10+
private static volatile InMemoryDatabasesCache _instance;
1111
private static readonly object _syncRoot = new object();
1212
private readonly ConcurrentDictionary<string, InMemoryDatabase> _dbs;
1313

1414
#endregion
1515

1616
#region Constructors
1717

18-
private InMemoryDatabaseStoreCache()
18+
private InMemoryDatabasesCache()
1919
{
2020
_dbs = new ConcurrentDictionary<string, InMemoryDatabase>();
2121
}
@@ -24,7 +24,7 @@ private InMemoryDatabaseStoreCache()
2424

2525
#region Properties
2626

27-
public static InMemoryDatabaseStoreCache Instance
27+
public static InMemoryDatabasesCache Instance
2828
{
2929
get
3030
{
@@ -33,7 +33,7 @@ public static InMemoryDatabaseStoreCache Instance
3333
lock (_syncRoot)
3434
{
3535
if (_instance == null)
36-
_instance = new InMemoryDatabaseStoreCache();
36+
_instance = new InMemoryDatabasesCache();
3737
}
3838
}
3939

src/DotNetToolkit.Repository.InMemory/Internal/InMemoryRepositoryContext.cs

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
using Configuration;
44
using Configuration.Conventions;
55
using Extensions;
6+
using InMemory.Properties;
67
using Query.Strategies;
78
using System;
89
using System.Collections.Generic;
910
using System.Data;
11+
using System.Globalization;
1012
using System.Linq;
1113
using Transactions;
1214
using Transactions.Internal;
@@ -21,7 +23,7 @@ internal class InMemoryRepositoryContext : LinqEnumerableRepositoryContextBase,
2123
private readonly bool _ignoreTransactionWarning;
2224
private readonly bool _ignoreSqlQueryWarning;
2325

24-
private readonly InMemoryUnderlyingDbContext _underlyingContext;
26+
private readonly InMemoryDatabase _db;
2527

2628
#endregion
2729

@@ -39,7 +41,7 @@ public InMemoryRepositoryContext(string databaseName, bool ignoreTransactionWarn
3941
_ignoreTransactionWarning = ignoreTransactionWarning;
4042
_ignoreSqlQueryWarning = ignoreSqlQueryWarning;
4143

42-
_underlyingContext = new InMemoryUnderlyingDbContext(databaseName, Conventions);
44+
_db = InMemoryDatabasesCache.Instance.GetDatabase(databaseName);
4345
}
4446

4547
#endregion
@@ -48,9 +50,9 @@ public InMemoryRepositoryContext(string databaseName, bool ignoreTransactionWarn
4850

4951
protected override IEnumerable<TEntity> AsEnumerable<TEntity>(IFetchQueryStrategy<TEntity> fetchStrategy)
5052
{
51-
return _underlyingContext
53+
return _db
5254
.FindAll<TEntity>()
53-
.ApplyFetchingOptions(fetchStrategy, _underlyingContext.FindAll);
55+
.ApplyFetchingOptions(fetchStrategy, _db.FindAll);
5456
}
5557

5658
#endregion
@@ -61,7 +63,7 @@ protected override IEnumerable<TEntity> AsEnumerable<TEntity>(IFetchQueryStrateg
6163

6264
public void EnsureDeleted()
6365
{
64-
_underlyingContext.ClearDatabase();
66+
_db.Clear();
6567
}
6668

6769
#endregion
@@ -80,22 +82,61 @@ public override ITransactionManager BeginTransaction()
8082

8183
public override void Add<TEntity>(TEntity entity)
8284
{
83-
_underlyingContext.Add(Guard.NotNull(entity, nameof(entity)));
85+
Guard.NotNull(entity, nameof(entity));
86+
87+
var entityType = typeof(TEntity);
88+
var keyValues = Conventions.GetPrimaryKeyValues(entity);
89+
90+
if (_db.TryFind<TEntity>(keyValues, out object _))
91+
{
92+
throw new InvalidOperationException(
93+
string.Format(
94+
CultureInfo.CurrentCulture,
95+
Resources.EntityAlreadyBeingTrackedInStore,
96+
entityType));
97+
}
98+
99+
if (TryGeneratePrimaryKey<TEntity>(entity, out var newKey))
100+
{
101+
// assumes we only have a single key since
102+
// we cannot generated for a composite key anyways
103+
keyValues[0] = newKey;
104+
}
105+
106+
_db.AddOrUpdate<TEntity>(entity, keyValues);
84107
}
85108

86109
public override void Update<TEntity>(TEntity entity)
87110
{
88-
_underlyingContext.Update(Guard.NotNull(entity, nameof(entity)));
111+
Guard.NotNull(entity, nameof(entity));
112+
113+
var keyValues = Conventions.GetPrimaryKeyValues(entity);
114+
115+
if (!_db.TryFind<TEntity>(keyValues, out object _))
116+
{
117+
throw new InvalidOperationException(Resources.EntityNotFoundInStore);
118+
}
119+
120+
_db.AddOrUpdate<TEntity>(entity, keyValues);
89121
}
90122

91123
public override void Remove<TEntity>(TEntity entity)
92124
{
93-
_underlyingContext.Remove(Guard.NotNull(entity, nameof(entity)));
125+
Guard.NotNull(entity, nameof(entity));
126+
127+
var keyValues = Conventions.GetPrimaryKeyValues(entity);
128+
129+
if (!_db.TryFind<TEntity>(keyValues, out object _))
130+
{
131+
throw new InvalidOperationException(Resources.EntityNotFoundInStore);
132+
}
133+
134+
_db.Remove<TEntity>(keyValues);
94135
}
95136

96137
public override int SaveChanges()
97138
{
98-
return _underlyingContext.SaveChanges();
139+
return -1;
99140
}
100141

101142
public override IEnumerable<TEntity> ExecuteSqlQuery<TEntity>(string sql, CommandType cmdType, Dictionary<string, object> parameters, Func<IDataReader, TEntity> projector)
@@ -125,9 +166,12 @@ public override TEntity Find<TEntity>(IFetchQueryStrategy<TEntity> fetchStrategy
125166

126167
if (fetchStrategy == null)
127168
{
128-
var result = _underlyingContext.Find<TEntity>(keyValues);
169+
if (_db.TryFind<TEntity>(keyValues, out object entity))
170+
{
171+
return (TEntity)Convert.ChangeType(entity, typeof(TEntity));
172+
}
129173

130-
return result;
174+
return default(TEntity);
131175
}
132176

133177
return base.Find(fetchStrategy, keyValues);
@@ -139,7 +183,6 @@ public override TEntity Find<TEntity>(IFetchQueryStrategy<TEntity> fetchStrategy
139183

140184
public override void Dispose()
141185
{
142-
_underlyingContext.Dispose();
143186
base.Dispose();
144187
}
145188

0 commit comments

Comments
 (0)