如何缓存'IQueryable<> .First'结果?

时间:2010-08-19 19:26:58

标签: .net caching lambda

我有两个类似的问题:

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

在这两种情况下,都会获取来自DB的常量数据。由于这个原因,我想缓存这些查询的结果......

一个请求的最简单的解决方案是:

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

我确实需要第二个实体的相似内容,而且还有更多内容......所以我想创建一个接受参数的类(CachableRepository),检查它们的对象是否已经缓存,如果没有 - 获取数据从DB并放入缓存。这应该适用于不同数量的参数..

问题是:我没有看到如何为不同参数创建缓存密钥的简单方法,以及如何为这些参数构建lambda函数...

如果您有任何想法或建议,请分享。

非常感谢!

2 个答案:

答案 0 :(得分:1)

我自己的'快速'解决方案:

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 :(得分:1)

我几乎到处都使用这个方法来处理ASP.NET缓存中的缓存对象,可以修改它来缓存在Dictionary中。

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