This is my current solution to this.
Given that, in a repository, we're going to have calls resembling:
public IEnumerable<MYPOCO> GetData(string someParameter, int anotherParameter);
We can therefore say that these parameters are criteria. So, I introduced a Criteria
class, which basically contains Dictionary<string, object>
instance, and has some type-safe setters and getters, simplified:
public class Criteria
{
private Dictionary<string, object> _criteria = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
public Criteria Set<T>(string key, T value)
{
_criteria[key] = value;
return this;
} // eo Set
public T Get<T>(string key)
{
return _criteria.ContainsKey(key) ? _criteria[key] : default(T);
} // eo Get
public Dictionary<string, object> Items { get { return _criteria; } }
} // eo class Criteria
Then, I wrote an extension method for Dictionary<TK, TV>
, based on this Stackoverflow answer. And finally, a IEqualityComparer<Criteria>
class that works with types of Criteria
.
This means my cache is now keyed by the criteria, which is set taking the parameters that were passed in to the repository:
public class MyPocoRepository<TMYPOCO>
{
private Cache<Criteria, IEnumerable<TMYPOCO>> _cache = new Cache<Criteria, IEnumerable<TMYPOCO>>(CriteriaComparer); // is passed to the dictionary constructor which is actually the cache.
public IEnumerable<TMYPOCO> GetData(string someParameter, int anotherParameter)
{
Criteria criteria = new Criteria();
criteria.Set("someParameter", someParameter)
.Set("anotherParameter", anotherParameter);
// we can check the cache now based on this...
} // eo GetData
} // eo MyPocoRepository<TMYPOCO>
Note that this also allows me to extend this idea when we want caching-strategies where the parameters are exactly the same, but perhaps a different user account is accessing it (we can add a field, say - the user-type, to the criteria, even if the LINQ expression isn't going to use it).