У меня 2 похожих запроса :
ICmOption optionRes = CmOptionRepository<ICmOption>
.GetAll()
.Where(option => option.Name == strCommandName && option.Data == strCommandOption)
.FirstOrDefault()
;
IErrorType errorType = ErrorTypeRepository<IErrorType>
.GetAll()
.Where(et => et.ComponentId == (int)component.Id && et.ComponentErrorCode == strErrorCode)
.First()
;
В обоих случаях извлекаются постоянные данные из БД, поэтому я хочу кэшировать результаты этих запросов ...
самое простое решение для одного запроса:
public IErrorType GetErrorType(IComponent component, string strErrorCode)
{
IErrorType errorType;
string strKey = string.Concat(component.Id, "_", strErrorCode);
lock (Dict)
{
if (Dict.ContainsKey(strKey))
{
errorType = Dict[strKey];
}
else
{
errorType = Repository
.GetAll()
.Where(et => et.ComponentId == (int)component.Id && et.ComponentErrorCode == strErrorCode)
.First()
;
Dict.Add(strKey, errorType);
}
}
return errorType;
}
private static Dictionary<string, IErrorType> Dict { get { return _dict; } }
private static readonly Dictionary<string, IErrorType> _dict
= new Dictionary<string, IErrorType>();
Мне нужно подобное для 2-е лицо, и еще несколько прибывают ... Поэтому я хочу создать класс (CachableRepository), который будет принимать параметры, проверять, кэшируется ли уже объект для них, если нет - получать данные из БД и помещать в кэш. И это должно работать для разного количества параметров.
Проблема в том, что я не вижу простого способа, как создать ключ для кэша для других параметров и как построить лямбда-функцию для этих параметров. ..
Если у вас есть какие-либо мысли или предложения, пожалуйста, поделитесь ими.
Большое спасибо!
Мое собственное "быстрое" решение:
internal class CacheManager<TIEntity>
where TIEntity : IEntity
{
internal TIEntity GetObject(string strKey, Func<TIEntity> funcGetEntity)
{
TIEntity entity;
lock (Dict)
{
if (Dict.ContainsKey(strKey))
{
entity = Dict[strKey];
}
else
{
entity = funcGetEntity();
Dict.Add(strKey, entity);
}
}
return entity;
}
private Dictionary<string, TIEntity> Dict { [DebuggerStepThrough] get { return _dict; } }
private readonly Dictionary<string, TIEntity> _dict = new Dictionary<string, TIEntity>();
}
public IErrorType GetErrorType(IComponent component, string strErrorCode)
{
string strKey = string.Concat(component.Id, "_", strErrorCode);
IErrorType errorType = _sCacheManager.GetObject(
strKey,
() => Repository
.GetAll()
.Where(et => et.ComponentId == (int)component.Id && et.ComponentErrorCode == strErrorCode)
.First()
);
return errorType;
}
private static CacheManager<IErrorType> _sCacheManager = new CacheManager<IErrorType>();
Пожалуйста, дайте мне знать, если вы видите лучший вариант.
Большое спасибо!
Я использую этот метод практически везде для обработки кэширования объектов в кэше ASP.NET, его можно модифицировать для кэширования в словаре.
public static T GetOrInsert<T>(string cacheKey, Func<T> creator)
{
object cacheItem = HttpRuntime.Cache.Get(cacheKey);
if (cacheItem is T)
{
return (T)cacheItem;
}
else
{
T newItem = creator();
HttpRuntime.Cache.Insert(cacheKey, newItem);
return newItem;
}
}
Затем вы можете использовать его как
public IErrorType GetErrorType(IComponent component, string strErrorCode)
{
string strKey = string.Concat(component.Id, "_", strErrorCode);
return CacheUtil.GetOrInsert<IErrorType>( strKey,
() => Repository
.GetAll()
.Where(et => et.ComponentId == (int)component.Id && et.ComponentErrorCode == strErrorCode)
.First()
);
}