Skip to content

Commit 63ed86a

Browse files
author
Jeff Treuting
committed
Added ability to clear cache for a repository
Fixes #68 Still need to find a way to do a global clear cache, which will be located at Cache.ClearAll() most likely
1 parent f7e8878 commit 63ed86a

12 files changed

Lines changed: 172 additions & 27 deletions
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
namespace SharpRepository.Repository.Caching
2+
{
3+
public static class Cache
4+
{
5+
// TODO: figure out how to do a global clear cache that clears for all repositories
6+
7+
// global counter used to clear all caches across all repositories
8+
private static int _globalCachingPrefixCounter = 1;
9+
internal static int GlobalCachingPrefixCounter
10+
{
11+
get { return _globalCachingPrefixCounter; }
12+
}
13+
14+
private static readonly object LockObject = new object();
15+
16+
// /// <summary>
17+
// /// This will clear out all SharpRepository related caching across all of the repositories
18+
// /// </summary>
19+
// public static void ClearAll()
20+
// {
21+
// // this increments a static counter by 1
22+
// // the static counter is used for all of the cache keys as part of the prefix
23+
// IncrementGlobalCachingPrefixCounter();
24+
// }
25+
//
26+
// internal static void IncrementGlobalCachingPrefixCounter()
27+
// {
28+
// Interlocked.Increment(ref _globalCachingPrefixCounter);
29+
// }
30+
}
31+
}

SharpRepository.Repository/Caching/CachingStrategyBase.cs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq.Expressions;
4+
using System.Runtime.Caching;
45
using SharpRepository.Repository.Queries;
56
using SharpRepository.Repository.Specifications;
67

@@ -9,9 +10,10 @@ namespace SharpRepository.Repository.Caching
910
public abstract class CachingStrategyBase<T, TKey> : ICachingStrategy<T, TKey> where T : class
1011
{
1112
private ICachingProvider _cachingProvider;
12-
public string CachePrefix { get; set; }
13+
public string CachePrefix { private get; set; }
1314
protected string TypeFullName { get; set; }
1415
public int? MaxResults { get; set; }
16+
private Type _entityType;
1517

1618
internal CachingStrategyBase()
1719
{
@@ -23,7 +25,8 @@ internal CachingStrategyBase(int? maxResults, ICachingProvider cachingProvider)
2325
CachingProvider = cachingProvider;
2426
MaxResults = maxResults;
2527

26-
TypeFullName = typeof(T).FullName ?? typeof(T).Name; // sometimes FullName returns null in certain derived type situations, so I added the check to use the Name property if FullName is null
28+
_entityType = typeof (T);
29+
TypeFullName = _entityType.FullName ?? _entityType.Name; // sometimes FullName returns null in certain derived type situations, so I added the check to use the Name property if FullName is null
2730
}
2831

2932
public ICachingProvider CachingProvider
@@ -32,6 +35,11 @@ public ICachingProvider CachingProvider
3235
set { _cachingProvider = value ?? new InMemoryCachingProvider(); }
3336
}
3437

38+
public string FullCachePrefix
39+
{
40+
get { return CachePrefix + Cache.GlobalCachingPrefixCounter + "-" + GetCachingPrefixCounter(); }
41+
}
42+
3543
public virtual bool TryGetResult(TKey key, out T result)
3644
{
3745
result = default(T);
@@ -220,6 +228,28 @@ protected bool SetCachedQueryOptions(string cacheKey, IQueryOptions<T> queryOpti
220228
return false;
221229
}
222230

231+
public void ClearAll()
232+
{
233+
IncrementCachingPrefixCounter();
234+
}
235+
236+
private int GetCachingPrefixCounter()
237+
{
238+
int counter;
239+
return !CachingProvider.Get(GetCachingPrefixCounterKey(), out counter) ? 1 : counter;
240+
}
241+
242+
private string GetCachingPrefixCounterKey()
243+
{
244+
// Note: it's important to use CachePrefix instead of FullCachePrefix otherwise it is tied to itself and won't be able to find it once the counter is incremented
245+
return String.Format("{0}/{1}/CachingPrefixCounter", CachePrefix, TypeFullName);
246+
}
247+
248+
private int IncrementCachingPrefixCounter()
249+
{
250+
return CachingProvider.Increment(GetCachingPrefixCounterKey(), 1, 1, CacheItemPriority.NotRemovable);
251+
}
252+
223253
protected void ClearCache(string cacheKey)
224254
{
225255
try

SharpRepository.Repository/Caching/ICachingStrategy.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ public interface ICachingStrategy<T, TKey>
2525
void Delete(TKey key, T result);
2626
void Save();
2727

28+
string FullCachePrefix { get; }
29+
void ClearAll();
30+
2831
ICachingProvider CachingProvider { get; set; }
2932
}
3033
}

SharpRepository.Repository/Caching/NoCachingStrategyBase.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ public void Save()
7676

7777
}
7878

79+
public string FullCachePrefix { get; private set; }
80+
81+
public void ClearAll()
82+
{
83+
84+
}
85+
7986
public ICachingProvider CachingProvider { get; set; }
8087
}
8188
}

SharpRepository.Repository/Caching/StandardCachingStrategyBase.cs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -318,29 +318,29 @@ private static void RecurseExpressionTree(string memberName, Expression expressi
318318

319319
protected override string GetAllCacheKey<TResult>(IQueryOptions<T> queryOptions, Expression<Func<T, TResult>> selector)
320320
{
321-
return String.Format("{0}/{1}/{2}/{3}", CachePrefix, TypeFullName, GetGeneration(), Md5Helper.CalculateMd5("All::" + (queryOptions != null ? queryOptions.ToString() : "null") + "::" + (selector != null ? selector.ToString() : "null")));
321+
return String.Format("{0}/{1}/{2}/{3}", FullCachePrefix, TypeFullName, GetGeneration(), Md5Helper.CalculateMd5("All::" + (queryOptions != null ? queryOptions.ToString() : "null") + "::" + (selector != null ? selector.ToString() : "null")));
322322
}
323323

324324
protected override string FindAllCacheKey<TResult>(ISpecification<T> criteria, IQueryOptions<T> queryOptions, Expression<Func<T, TResult>> selector)
325325
{
326326
TPartition partition;
327327
if (TryPartitionValue(criteria, out partition))
328328
{
329-
return String.Format("{0}/{1}/p:{2}/{3}/{4}/{5}", CachePrefix, TypeFullName, partition, GetPartitionGeneration(partition), "FindAll", Md5Helper.CalculateMd5(criteria + "::" + (queryOptions != null ? queryOptions.ToString() : "null") + "::" + (selector != null ? selector.ToString() : "null")));
329+
return String.Format("{0}/{1}/p:{2}/{3}/{4}/{5}", FullCachePrefix, TypeFullName, partition, GetPartitionGeneration(partition), "FindAll", Md5Helper.CalculateMd5(criteria + "::" + (queryOptions != null ? queryOptions.ToString() : "null") + "::" + (selector != null ? selector.ToString() : "null")));
330330
}
331331

332-
return String.Format("{0}/{1}/{2}/{3}/{4}", CachePrefix, TypeFullName, GetGeneration(), "FindAll", Md5Helper.CalculateMd5(criteria + "::" + (queryOptions != null ? queryOptions.ToString() : "null") + "::" + (selector != null ? selector.ToString() : "null")));
332+
return String.Format("{0}/{1}/{2}/{3}/{4}", FullCachePrefix, TypeFullName, GetGeneration(), "FindAll", Md5Helper.CalculateMd5(criteria + "::" + (queryOptions != null ? queryOptions.ToString() : "null") + "::" + (selector != null ? selector.ToString() : "null")));
333333
}
334334

335335
protected override string FindCacheKey<TResult>(ISpecification<T> criteria, IQueryOptions<T> queryOptions, Expression<Func<T, TResult>> selector)
336336
{
337337
TPartition partition;
338338
if (TryPartitionValue(criteria, out partition))
339339
{
340-
return String.Format("{0}/{1}/p:{2}/{3}/{4}/{5}", CachePrefix, TypeFullName, partition, GetPartitionGeneration(partition), "Find", Md5Helper.CalculateMd5(criteria + "::" + (queryOptions != null ? queryOptions.ToString() : "null") + "::" + (selector != null ? selector.ToString() : "null")));
340+
return String.Format("{0}/{1}/p:{2}/{3}/{4}/{5}", FullCachePrefix, TypeFullName, partition, GetPartitionGeneration(partition), "Find", Md5Helper.CalculateMd5(criteria + "::" + (queryOptions != null ? queryOptions.ToString() : "null") + "::" + (selector != null ? selector.ToString() : "null")));
341341
}
342342

343-
return String.Format("{0}/{1}/{2}/{3}/{4}", CachePrefix, TypeFullName, GetGeneration(), "Find", Md5Helper.CalculateMd5(criteria + "::" + (queryOptions != null ? queryOptions.ToString() : "null") + "::" + (selector != null ? selector.ToString() : "null")));
343+
return String.Format("{0}/{1}/{2}/{3}/{4}", FullCachePrefix, TypeFullName, GetGeneration(), "Find", Md5Helper.CalculateMd5(criteria + "::" + (queryOptions != null ? queryOptions.ToString() : "null") + "::" + (selector != null ? selector.ToString() : "null")));
344344
}
345345

346346
private int GetGeneration()
@@ -353,14 +353,12 @@ private int GetGeneration()
353353

354354
private int IncrementGeneration()
355355
{
356-
var generation = !GenerationalCachingEnabled ? 1 : CachingProvider.Increment(GetGenerationKey(), 1, 1, CacheItemPriority.NotRemovable);
357-
358-
return generation;
356+
return !GenerationalCachingEnabled ? 1 : CachingProvider.Increment(GetGenerationKey(), 1, 1, CacheItemPriority.NotRemovable);
359357
}
360358

361359
private string GetGenerationKey()
362360
{
363-
return String.Format("{0}/{1}/Generation", CachePrefix, TypeFullName);
361+
return String.Format("{0}/{1}/Generation", FullCachePrefix, TypeFullName);
364362
}
365363

366364
private int GetPartitionGeneration(TPartition partition)
@@ -378,7 +376,7 @@ private int IncrementPartitionGeneration(TPartition partition)
378376

379377
protected string GetPartitionGenerationKey(TPartition partition)
380378
{
381-
return String.Format("{0}/{1}/p:{2}/Generation", CachePrefix, TypeFullName, partition);
379+
return String.Format("{0}/{1}/p:{2}/Generation", FullCachePrefix, TypeFullName, partition);
382380
}
383381
}
384382
}

SharpRepository.Repository/Caching/TimeoutCachingStrategyBase.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,17 @@ public override void Save()
5959

6060
protected override string GetAllCacheKey<TResult>(IQueryOptions<T> queryOptions, Expression<Func<T, TResult>> selector)
6161
{
62-
return String.Format("{0}/{1}/{2}", CachePrefix, TypeFullName, Md5Helper.CalculateMd5("All::" + (queryOptions != null ? queryOptions.ToString() : "null") + "::" + (selector != null ? selector.ToString() : "null")));
62+
return String.Format("{0}/{1}/{2}", FullCachePrefix, TypeFullName, Md5Helper.CalculateMd5("All::" + (queryOptions != null ? queryOptions.ToString() : "null") + "::" + (selector != null ? selector.ToString() : "null")));
6363
}
6464

6565
protected override string FindAllCacheKey<TResult>(ISpecification<T> criteria, IQueryOptions<T> queryOptions, Expression<Func<T, TResult>> selector)
6666
{
67-
return String.Format("{0}/{1}/{2}/{3}", CachePrefix, TypeFullName, "FindAll", Md5Helper.CalculateMd5(criteria + "::" + (queryOptions != null ? queryOptions.ToString() : "null") + "::" + (selector != null ? selector.ToString() : "null")));
67+
return String.Format("{0}/{1}/{2}/{3}", FullCachePrefix, TypeFullName, "FindAll", Md5Helper.CalculateMd5(criteria + "::" + (queryOptions != null ? queryOptions.ToString() : "null") + "::" + (selector != null ? selector.ToString() : "null")));
6868
}
6969

7070
protected override string FindCacheKey<TResult>(ISpecification<T> criteria, IQueryOptions<T> queryOptions, Expression<Func<T, TResult>> selector)
7171
{
72-
return String.Format("{0}/{1}/{2}/{3}", CachePrefix, TypeFullName, "Find", Md5Helper.CalculateMd5(criteria + "::" + (queryOptions != null ? queryOptions.ToString() : "null") + "::" + (selector != null ? selector.ToString() : "null")));
72+
return String.Format("{0}/{1}/{2}/{3}", FullCachePrefix, TypeFullName, "Find", Md5Helper.CalculateMd5(criteria + "::" + (queryOptions != null ? queryOptions.ToString() : "null") + "::" + (selector != null ? selector.ToString() : "null")));
7373
}
7474
}
7575
}

SharpRepository.Repository/ConfigurationBasedRepository.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,11 @@ public IDisabledCache DisableCaching()
244244
return Repository.DisableCaching();
245245
}
246246

247+
public void ClearCache()
248+
{
249+
Repository.ClearCache();
250+
}
251+
247252
public ICachingStrategy<T, TKey> CachingStrategy
248253
{
249254
get { return Repository.CachingStrategy; }

SharpRepository.Repository/IRepository.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,26 @@ public interface IRepository<T, TKey> : IRepositoryBase<T>, IRepositoryQueryable
6464

6565
ICachingStrategy<T, TKey> CachingStrategy { get; set; }
6666

67+
/// <summary>
68+
/// Used to get or set whether the cache is currently enabled and being used
69+
/// </summary>
6770
bool CachingEnabled { get; set; }
6871

72+
/// <summary>
73+
/// Returns true if the cache was used on the very last query that was used (Get, Find, GetAll or FindAll)
74+
/// </summary>
6975
bool CacheUsed { get; }
7076

77+
/// <summary>
78+
/// Disables caching for all code within the using() block it is called in
79+
/// </summary>
80+
/// <returns></returns>
7181
IDisabledCache DisableCaching();
82+
83+
/// <summary>
84+
/// Clears the cache for this particular repository. All other repositories will still have their caches available. Use Repository.ClearAllCache() to clear the cache for every repository
85+
/// </summary>
86+
void ClearCache();
7287
}
7388

7489
/// <summary>

SharpRepository.Repository/RepositoryBase.cs

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,22 @@ public abstract partial class RepositoryBase<T, TKey> : IRepository<T, TKey> whe
1919
// the query manager uses the caching strategy to determine if it should check the cache or run the query
2020
private QueryManager<T, TKey> _queryManager;
2121

22+
private readonly Type _entityType;
23+
24+
protected RepositoryBase(ICachingStrategy<T, TKey> cachingStrategy = null)
25+
{
26+
if (typeof(T) == typeof(TKey))
27+
{
28+
// this check is mainly because of the overloaded Delete methods Delete(T) and Delete(TKey), ambiguous reference if the generics are the same
29+
throw new InvalidOperationException("The repository type and the primary key type can not be the same.");
30+
}
31+
32+
CachingStrategy = cachingStrategy ?? new NoCachingStrategy<T, TKey>();
33+
_entityType = typeof(T);
34+
_typeName = _entityType.Name;
35+
Conventions = new RepositoryConventions();
36+
}
37+
2238
// conventions
2339
public IRepositoryConventions Conventions { get; set; }
2440

@@ -47,21 +63,13 @@ public IDisabledCache DisableCaching()
4763
// This ensures that a repository alone can initiate a new batch.
4864
return new DisabledCache(this);
4965
}
50-
51-
private bool BatchMode { get; set; }
5266

53-
protected RepositoryBase(ICachingStrategy<T, TKey> cachingStrategy = null)
67+
public void ClearCache()
5468
{
55-
if (typeof(T) == typeof(TKey))
56-
{
57-
// this check is mainly because of the overloaded Delete methods Delete(T) and Delete(TKey), ambiguous reference if the generics are the same
58-
throw new InvalidOperationException("The repository type and the primary key type can not be the same.");
59-
}
60-
61-
CachingStrategy = cachingStrategy ?? new NoCachingStrategy<T, TKey>();
62-
_typeName = typeof (T).Name;
63-
Conventions = new RepositoryConventions();
69+
CachingStrategy.ClearAll();
6470
}
71+
72+
private bool BatchMode { get; set; }
6573

6674
public ICachingStrategy<T, TKey> CachingStrategy
6775
{

SharpRepository.Repository/SharpRepository.Repository.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
<Compile Include="DisabledCache.cs" />
9393
<Compile Include="IDisabledCache.cs" />
9494
<Compile Include="Queries\IPagingOptions.cs" />
95+
<Compile Include="Caching\Cache.cs" />
9596
<Compile Include="RepositoryConventions.cs" />
9697
<Compile Include="DefaultRepositoryConventions.cs" />
9798
<Compile Include="Helpers\ExpressionHelper.cs" />

0 commit comments

Comments
 (0)