Skip to content

Commit 76eac08

Browse files
author
Jeff Treuting
committed
Create CacheRepository
1 parent 31262bc commit 76eac08

27 files changed

Lines changed: 426 additions & 7 deletions
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using SharpRepository.Repository;
2+
using SharpRepository.Repository.Configuration;
3+
4+
namespace SharpRepository.CacheRepository
5+
{
6+
public class CacheConfigRepositoryFactory : ConfigRepositoryFactory
7+
{
8+
public CacheConfigRepositoryFactory(IRepositoryConfiguration config)
9+
: base(config)
10+
{
11+
}
12+
13+
public override IRepository<T, TKey> GetInstance<T, TKey>()
14+
{
15+
return new CacheRepository<T, TKey>(RepositoryConfiguration["prefix"]);
16+
}
17+
}
18+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using SharpRepository.Repository;
2+
using SharpRepository.Repository.Caching;
3+
4+
namespace SharpRepository.CacheRepository
5+
{
6+
public class CacheRepository<T, TKey> : CacheRepositoryBase<T, TKey> where T : class, new()
7+
{
8+
public CacheRepository(string prefix, ICachingProvider cachingProvider, ICachingStrategy<T, TKey> cachingStrategy = null)
9+
: base(prefix, cachingProvider, cachingStrategy)
10+
{
11+
}
12+
13+
public CacheRepository(string prefix, ICachingStrategy<T, TKey> cachingStrategy = null)
14+
: base(prefix, cachingStrategy)
15+
{
16+
}
17+
}
18+
19+
public class CacheRepository<T> : CacheRepositoryBase<T, int>, IRepository<T> where T : class, new()
20+
{
21+
public CacheRepository(string prefix, ICachingProvider cachingProvider, ICachingStrategy<T, int> cachingStrategy = null)
22+
: base(prefix, cachingProvider, cachingStrategy)
23+
{
24+
}
25+
26+
public CacheRepository(string prefix, ICachingStrategy<T, int> cachingStrategy = null)
27+
: base(prefix, cachingStrategy)
28+
{
29+
}
30+
}
31+
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
using System;
2+
using System.Collections.Concurrent;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using SharpRepository.Repository;
6+
using SharpRepository.Repository.Caching;
7+
using SharpRepository.Repository.FetchStrategies;
8+
9+
namespace SharpRepository.CacheRepository
10+
{
11+
public abstract class CacheRepositoryBase<T, TKey> : LinqRepositoryBase<T, TKey> where T : class, new()
12+
{
13+
private readonly string _prefix;
14+
private readonly ICachingProvider _cachingProvider;
15+
16+
internal CacheRepositoryBase(string prefix, ICachingStrategy<T, TKey> cachingStrategy = null)
17+
: this(prefix, new InMemoryCachingProvider(), cachingStrategy)
18+
{
19+
}
20+
21+
internal CacheRepositoryBase(string prefix, ICachingProvider cachingProvider, ICachingStrategy<T, TKey> cachingStrategy = null)
22+
: base(cachingStrategy)
23+
{
24+
_prefix = prefix;
25+
_cachingProvider = cachingProvider;
26+
}
27+
28+
private ConcurrentDictionary<TKey, T> Items
29+
{
30+
get
31+
{
32+
ConcurrentDictionary<TKey, T> items = null;
33+
34+
if (!_cachingProvider.Exists(_prefix + ".CacheRepository.Items"))
35+
{
36+
items = new ConcurrentDictionary<TKey, T>();
37+
_cachingProvider.Set(_prefix + ".CacheRepository.Items", items);
38+
}
39+
else
40+
{
41+
if (!_cachingProvider.Get(_prefix + ".CacheRepository.Items", out items))
42+
{
43+
items = new ConcurrentDictionary<TKey, T>();
44+
}
45+
}
46+
47+
return items;
48+
}
49+
set
50+
{
51+
_cachingProvider.Set(_prefix + ".CacheRepository.Items", value);
52+
}
53+
}
54+
55+
protected override IQueryable<T> BaseQuery(IFetchStrategy<T> fetchStrategy = null)
56+
{
57+
return CloneDictionary(Items).AsQueryable();
58+
}
59+
60+
protected override T GetQuery(TKey key)
61+
{
62+
T result;
63+
Items.TryGetValue(key, out result);
64+
65+
return result;
66+
}
67+
68+
private static IEnumerable<T> CloneDictionary(ConcurrentDictionary<TKey, T> list)
69+
{
70+
// when you Google deep copy of generic list every answer uses either the IClonable interface on the T or having the T be Serializable
71+
// since we can't really put those constraints on T I'm going to do it via reflection
72+
73+
var type = typeof (T);
74+
var properties = type.GetProperties();
75+
76+
var clonedList = new List<T>(list.Count);
77+
78+
foreach (var keyValuePair in list)
79+
{
80+
var newItem = new T();
81+
foreach (var propInfo in properties)
82+
{
83+
propInfo.SetValue(newItem, propInfo.GetValue(keyValuePair.Value, null), null);
84+
}
85+
86+
clonedList.Add(newItem);
87+
}
88+
89+
return clonedList;
90+
}
91+
92+
protected override void AddItem(T entity)
93+
{
94+
TKey id;
95+
96+
if (GetPrimaryKey(entity, out id) && Equals(id, default(TKey)))
97+
{
98+
id = GeneratePrimaryKey();
99+
SetPrimaryKey(entity, id);
100+
}
101+
102+
Items[id] = entity;
103+
}
104+
105+
protected override void DeleteItem(T entity)
106+
{
107+
TKey pkValue;
108+
GetPrimaryKey(entity, out pkValue);
109+
110+
T tmp;
111+
Items.TryRemove(pkValue, out tmp);
112+
}
113+
114+
protected override void UpdateItem(T entity)
115+
{
116+
TKey pkValue;
117+
GetPrimaryKey(entity, out pkValue);
118+
119+
Items[pkValue] = entity;
120+
}
121+
122+
protected override void SaveChanges()
123+
{
124+
125+
}
126+
127+
public override void Dispose()
128+
{
129+
130+
}
131+
132+
private TKey GeneratePrimaryKey()
133+
{
134+
if (typeof(TKey) == typeof(Guid))
135+
{
136+
return (TKey)Convert.ChangeType(Guid.NewGuid(), typeof(TKey));
137+
}
138+
139+
if (typeof(TKey) == typeof(string))
140+
{
141+
return (TKey)Convert.ChangeType(Guid.NewGuid().ToString("N"), typeof(TKey));
142+
}
143+
144+
if (typeof(TKey) == typeof(Int32))
145+
{
146+
var pkValue = Items.Keys.LastOrDefault();
147+
148+
var nextInt = Convert.ToInt32(pkValue) + 1;
149+
return (TKey)Convert.ChangeType(nextInt, typeof(TKey));
150+
}
151+
152+
throw new InvalidOperationException("Primary key could not be generated. This only works for GUID, Int32 and String.");
153+
}
154+
155+
public override string ToString()
156+
{
157+
return "SharpRepository.InMemoryRepository";
158+
}
159+
}
160+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using SharpRepository.Repository.Configuration;
2+
3+
namespace SharpRepository.CacheRepository
4+
{
5+
public class CacheRepositoryConfiguration : RepositoryConfiguration
6+
{
7+
public CacheRepositoryConfiguration(string name, string cachingStrategy = null, string cachingProvider = null)
8+
: this(name, "", cachingStrategy, cachingProvider)
9+
{
10+
}
11+
12+
public CacheRepositoryConfiguration(string name, string prefix, string cachingStrategy=null, string cachingProvider=null)
13+
: base(name)
14+
{
15+
Prefix = prefix;
16+
CachingStrategy = cachingStrategy;
17+
CachingProvider = cachingProvider;
18+
Factory = typeof(CacheConfigRepositoryFactory);
19+
}
20+
21+
public string Prefix
22+
{
23+
set { Attributes["prefix"] = value; }
24+
}
25+
}
26+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace SharpRepository.CacheRepository
2+
{
3+
public interface IAmInCacheRepository
4+
{
5+
}
6+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyTitle("SharpRepository.CacheRepository")]
9+
[assembly: AssemblyDescription("")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("")]
12+
[assembly: AssemblyProduct("SharpRepository.CacheRepository")]
13+
[assembly: AssemblyCopyright("Copyright © 2013")]
14+
[assembly: AssemblyTrademark("")]
15+
[assembly: AssemblyCulture("")]
16+
17+
// Setting ComVisible to false makes the types in this assembly not visible
18+
// to COM components. If you need to access a type in this assembly from
19+
// COM, set the ComVisible attribute to true on that type.
20+
[assembly: ComVisible(false)]
21+
22+
// The following GUID is for the ID of the typelib if this project is exposed to COM
23+
[assembly: Guid("93a961ad-26d2-4e9b-8e45-c164e16f99ae")]
24+
25+
// Version information for an assembly consists of the following four values:
26+
//
27+
// Major Version
28+
// Minor Version
29+
// Build Number
30+
// Revision
31+
//
32+
// You can specify all the values or you can default the Build and Revision Numbers
33+
// by using the '*' as shown below:
34+
// [assembly: AssemblyVersion("1.0.*")]
35+
[assembly: AssemblyVersion("1.0.0.0")]
36+
[assembly: AssemblyFileVersion("1.0.0.0")]
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<ProjectGuid>{42E07863-9017-4B56-9D20-1EA35AF1F501}</ProjectGuid>
8+
<OutputType>Library</OutputType>
9+
<AppDesignerFolder>Properties</AppDesignerFolder>
10+
<RootNamespace>SharpRepository.CacheRepository</RootNamespace>
11+
<AssemblyName>SharpRepository.CacheRepository</AssemblyName>
12+
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
13+
<FileAlignment>512</FileAlignment>
14+
<TargetFrameworkProfile />
15+
</PropertyGroup>
16+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
17+
<DebugSymbols>true</DebugSymbols>
18+
<DebugType>full</DebugType>
19+
<Optimize>false</Optimize>
20+
<OutputPath>bin\Debug\</OutputPath>
21+
<DefineConstants>DEBUG;TRACE</DefineConstants>
22+
<ErrorReport>prompt</ErrorReport>
23+
<WarningLevel>4</WarningLevel>
24+
</PropertyGroup>
25+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
26+
<DebugType>pdbonly</DebugType>
27+
<Optimize>true</Optimize>
28+
<OutputPath>bin\Release\</OutputPath>
29+
<DefineConstants>TRACE</DefineConstants>
30+
<ErrorReport>prompt</ErrorReport>
31+
<WarningLevel>4</WarningLevel>
32+
</PropertyGroup>
33+
<ItemGroup>
34+
<Reference Include="System" />
35+
<Reference Include="System.Core" />
36+
<Reference Include="System.Runtime.Caching" />
37+
</ItemGroup>
38+
<ItemGroup>
39+
<Compile Include="CacheRepositoryBase.cs" />
40+
<Compile Include="CacheRepository.cs" />
41+
<Compile Include="Properties\AssemblyInfo.cs" />
42+
</ItemGroup>
43+
<ItemGroup>
44+
<ProjectReference Include="..\SharpRepository.Repository\SharpRepository.Repository.csproj">
45+
<Project>{710DEE79-25CE-4F68-B8B1-D08A135AD154}</Project>
46+
<Name>SharpRepository.Repository</Name>
47+
</ProjectReference>
48+
</ItemGroup>
49+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
50+
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
51+
Other similar extension points exist, see Microsoft.Common.targets.
52+
<Target Name="BeforeBuild">
53+
</Target>
54+
<Target Name="AfterBuild">
55+
</Target>
56+
-->
57+
</Project>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace SharpRepository.Tests.Integration.Data
2+
{
3+
public class CachePrefixFactory
4+
{
5+
private static int _num = 1;
6+
7+
public static string Build()
8+
{
9+
_num++; // since it goes through and calls this for each test before running them, we need a different database for each test or else the auto increment goes to 2 on the second test with an add and it fails
10+
// surprisingly the timing isn;'t too bad for this, the first test takes about 7 secs for EF to model the DB and create it, then each other test is super quick in creating the DB file
11+
12+
13+
return _num.ToString();
14+
}
15+
}
16+
}

SharpRepository.Tests.Integration/Data/RepositoryTestCaseDataFactory.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
using SharpRepository.RavenDbRepository;
1313
using SharpRepository.MongoDbRepository;
1414
using SharpRepository.InMemoryRepository;
15+
using SharpRepository.CacheRepository;
16+
1517

1618
namespace SharpRepository.Tests.Integration.Data
1719
{
@@ -65,6 +67,11 @@ public static IEnumerable<TestCaseData> Build(RepositoryTypes[] includeTypes)
6567
};
6668
yield return new TestCaseData(new RavenDbRepository<Contact, string>(documentStore)).SetName("RavenDbRepository Test");
6769
}
70+
71+
if (includeTypes.Contains(RepositoryTypes.Cache))
72+
{
73+
yield return new TestCaseData(new CacheRepository<Contact, string>(CachePrefixFactory.Build())).SetName("CacheRepository Test");
74+
}
6875
}
6976
}
7077
}

SharpRepository.Tests.Integration/RepositoryTypes.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public enum RepositoryTypes
77
Ef5,
88
RavenDb,
99
Dbo4,
10-
MongoDb
10+
MongoDb,
11+
Cache
1112
}
1213
}

0 commit comments

Comments
 (0)