Как кэшировать результат 'IQueryable <>. First' ?

У меня 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), который будет принимать параметры, проверять, кэшируется ли уже объект для них, если нет - получать данные из БД и помещать в кэш. И это должно работать для разного количества параметров.

Проблема в том, что я не вижу простого способа, как создать ключ для кэша для других параметров и как построить лямбда-функцию для этих параметров. ..

Если у вас есть какие-либо мысли или предложения, пожалуйста, поделитесь ими.

Большое спасибо!

1
задан Budda 19 August 2010 в 19:26
поделиться

2 ответа

Мое собственное "быстрое" решение:

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>();

Пожалуйста, дайте мне знать, если вы видите лучший вариант.

Большое спасибо!

1
ответ дан 2 September 2019 в 21:59
поделиться

Я использую этот метод практически везде для обработки кэширования объектов в кэше 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()
    );
}
1
ответ дан 2 September 2019 в 21:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: