我有一个基本的存储库框架,最终执行查询并将结果映射回对象:
例如:
public SomeEntity Get(id)
{
return base.GetItem<SomeEntity>
("select * from SomeEntities where id = @idParam",
new { idParam = id});
}
如果这看起来像Dapper,那是因为引擎盖下的GetItem正在包装Dapper。
我想为GetItem添加自动缓存,我有两个参数:
我担心对这些参数执行简单的主要哈希会导致缓存密钥冲突,当您从缓存中提取数据时,冲突可能会非常糟糕(I.E.泄漏敏感 信息)。
那么,我有哪些技术可以生成合理大小的缓存键,同时保证基于查询和参数输入的唯一性?
答案 0 :(得分:6)
我使用以下扩展方法来制作委托的缓存版本:
public static Func<T, TResult> AsCached<T, TResult>(this Func<T, TResult> function)
{
var cachedResults = new Dictionary<T, TResult>();
return (argument) =>
{
TResult result;
lock (cachedResults)
{
if (!cachedResults.TryGetValue(argument, out result))
{
result = function(argument);
cachedResults.Add(argument, result);
}
}
return result;
};
}
public static Func<T1, T2, TResult> AsCached<T1, T2, TResult>(this Func<T1, T2, TResult> function)
{
var cachedResults = new Dictionary<Tuple<T1, T2>, TResult>();
return (value1, value2) =>
{
TResult result;
var paramsTuple = new Tuple<T1, T2>(value1, value2);
lock(cachedResults)
{
if (!cachedResults.TryGetValue(paramsTuple, out result))
{
result = function(value1, value2);
cachedResults.Add(paramsTuple, result);
}
}
return result;
};
}
public static Func<T1, T2, T3, TResult> AsCached<T1, T2, T3, TResult>(this Func<T1, T2, T3, TResult> function)
{
var cachedResults = new Dictionary<Tuple<T1, T2, T3>, TResult>();
return (value1, value2, value3) =>
{
TResult result;
var paramsTuple = new Tuple<T1, T2, T3>(value1, value2, value3);
lock(cachedResults)
{
if (!cachedResults.TryGetValue(paramsTuple, out result))
{
result = function(value1, value2, value3);
cachedResults.Add(paramsTuple, result);
}
}
return result;
};
}
等等N个参数...
如果从代码中不清楚,我使用参数创建一个元组,并使用元组作为字典的键,该字典包含每组参数的返回值。请注意,每次调用AsCached
时,都会创建一个单独的缓存。
您可以按如下方式使用这些方法:
private Func<int, SomeEntity> _getCached;
public SomeEntity Get(int id)
{
if (_getCached == null)
{
Func<int, SomeEntity> func = GetImpl;
_getCached = func.AsCached();
}
return _getCached(id);
}
private SomeEntity GetImpl(int id)
{
return base.GetItem<SomeEntity>
("select * from SomeEntities where id = @idParam",
new { idParam = id});
}
答案 1 :(得分:3)
我看到了一些选项
将数据打包到类中,使用BinaryFormatter序列化类并对序列化数据执行SHA1哈希,以便为您提供哈希键。
将数据打包成一个类,实现IEqualityComparer,然后将其存储在Dictionary中。通过实现IEqualityComparer,您将控制Hash的生成以及执行的数据比较,以便在发生冲突时识别唯一数据。