代码之家  ›  专栏  ›  技术社区  ›  Budda

如何缓存“iQueryable<>.First”结果?

  •  1
  • Budda  · 技术社区  · 15 年前

    我有两个类似的问题:

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

    我确实需要类似的第二实体,而且很少有更多的是来…所以我想创建一个类(cachablerepository),它将接受参数,检查是否已经缓存了它们的对象,如果没有,从数据库中获取数据并放入缓存。这应该适用于不同数量的参数。

    问题是:我看不到一个简单的方法,如何为不同的参数创建缓存键,以及如何为这些参数构建lambda函数…

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

    谢谢!

    2 回复  |  直到 15 年前
        1
  •  1
  •   Budda    15 年前

    我自己的“快速”解决方案:

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

    如果你看到更好的选择,请告诉我。

    谢谢!

        2
  •  1
  •   stevemegson    15 年前

    我几乎在任何地方都使用这个方法来处理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()
        );
    }