• C# 数据权限缓存


      最近做一个C#项目,刚做完数据权限,现把缓存机制给大家分享一下:

      做过数据权限的同学应该都知道,每次涉及到查询数据时都会去数据库把配置好的数据权限查询出来,这样每次在操作是会很慢。数据权限实现其实就是在数据库表的基础上加上查询条件,然后按照不同角色分配,这样拼出一个查询条件保存在数据库,然后每次打开一个页面时,会根据当前页面对应的实体去数据库表查询配置好的权限,接下来是把这个权限条件带入已写好的后台代码查询语句中,这样就实现了数据权限的机制。那么我们每次点开一个新页面都会去数据库查询一下当前用户的角色对应的数据权限,这样会频繁的连接数据库,用户多了之后肯定就会特别慢。因为数据权限一旦配好之后就会很少去改动它,所以我们可以做一个缓存把每次查询出来的数据权限缓存起来,这样就可以提高查询效率。好了,废话不多说了,上代码。

      我声明一下我用的是Dictionary数据字典,您也可以使用Cache等等别的技术,实现机制都一样。

         我使用了一个接口,一个抽象类,一个工厂类,一个普通类。

      首先我们得定义设置缓存,获取缓存,删除缓存的方法,还要定义缓存的大小,太大了就会不好控制,消耗内存。在接口中定义方法,然后用抽象类继承接口实现方法,因为缓存是一直保存在整个网站运行期间,所以不能实例化它,我们得用abstract类,用工厂模式实现调用。 需要注意一点就是我们可以定义Dictionary里面的类型为泛型类而不用object类型,这样在使用的时候就不用装箱,拆箱。

     以下是接口ICache代码:

    /// <summary>
    /// 设置缓存
    /// </summary>
    /// <param name="key"></param>
    /// <param name="value"></param>
    void SetCache(TKey key, TValue value);

    /// <summary>
    /// 获取缓存
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    TValue GetCache(TKey key);


    /// <summary>
    /// 清空指定缓存
    /// </summary>
    void Clear(TKey key);

    /// <summary>
    /// 清空当前登录用户的缓存
    /// </summary>
    /// <param name="key"></param>
    void ClearAll();

    /// <summary>
    /// 定义缓存Key
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    TKey JoinKey(TKey key);

    /// <summary>
    /// 缓存大小
    /// </summary>
    int CacheSize { get; set; }

      接着,我们用一个抽象类(AbstractCache)继承接口,这里面的大部分都是虚方法,因为我们在使用的时候考虑到还有别的缓存,所以可以在继承类里面重写这些方法。

    public AbstractCache(string type)
    {
    this._type = type;
    if (AbstractCache<TKey, TValue>._cacheList == null)
    {
    AbstractCache<TKey, TValue>._cacheList = new Dictionary<string, Dictionary<TKey, TValue>>();
    }
    if (!AbstractCache<TKey, TValue>._cacheList.ContainsKey(_type))
    {
    AbstractCache<TKey, TValue>._cacheList.Add(this._type, new Dictionary<TKey, TValue>());
    }
    }
    private static Dictionary<string, Dictionary<TKey, TValue>> _cacheList;
    private string _type;
    private int _cacheSize = 100;

    public virtual void SetCache(TKey key, TValue value)
    {
    Dictionary<TKey, TValue> dic = this.getTypeCache();
    lock (AbstractCache<TKey, TValue>._cacheList)
    {
    TKey fullKey = this.JoinKey(key);
    if (!dic.ContainsKey(fullKey))
    {
    if (dic.Count >= this._cacheSize)
    {
    if (dic.Keys.Count > 0)
    {
    TKey tmpKey = default(TKey);
    foreach (TKey k in dic.Keys)
    {
    tmpKey = k;
    break;
    }
    dic.Remove(tmpKey);
    }
    }
    if (value != null)
    {
    dic.Add(fullKey, value);
    }
    else
    {
    dic.Add(fullKey, default(TValue));
    }
    }
    else
    {
    if (value != null)
    {
    dic[fullKey] = value;
    }
    else
    {
    dic[fullKey] = default(TValue);
    }
    }
    }
    }


    public virtual TValue GetCache(TKey key)
    {
    Dictionary<TKey, TValue> dic = this.getTypeCache();
    TKey fullKey = this.JoinKey(key);
    if (dic.ContainsKey(fullKey))
    {
    return dic[fullKey];
    }
    return default(TValue);
    }

    public virtual void Clear(TKey key)
    {
    Dictionary<TKey, TValue> dic = this.getTypeCache();
    lock (AbstractCache<TKey, TValue>._cacheList)
    {
    TKey fullKey = this.JoinKey(key);
    if (dic.ContainsKey(fullKey))
    {
    dic.Remove(fullKey);
    }
    }
    }
    public virtual void ClearAll()
    {
    throw new NotImplementedException();
    }

    public abstract TKey JoinKey(TKey key);


    public int CacheSize
    {
    get
    {
    return _cacheSize;
    }
    set
    {
    _cacheSize = value;
    }
    }

    /// <summary>
    /// 获取当前类型的缓存数据
    /// </summary>
    /// <returns></returns>
    protected Dictionary<TKey, TValue> getTypeCache()
    {
    Dictionary<TKey, TValue> dic = AbstractCache<TKey, TValue>._cacheList[this._type];
    if (dic == null)
    {
    throw new Exception("不正确的初始化方式");
    }
    return dic;
    }

    接下来我们需要顶一个DataAuthCache类来继承抽象类重写一些自己需要的方法,

    public DataAuthCache()
    : base("DataAuthCache")  //这个参数是区分缓存那一部分类容的
    {
    }
    private static object _lockObj = new object();
    public override string JoinKey(string entityName)
    {
    return Entity.Session.Manage.Current.AuthContext.OrgID + "_" + Entity.Session.Manage.Current.AuthContext.UserID + "_" + entityName;
    }
    public override void ClearAll()
    {
    long orgKey = Entity.Session.Manage.Current.AuthContext.OrgID;
    long userKey = Entity.Session.Manage.Current.AuthContext.UserID;
    lock (_lockObj)
    {
    Dictionary<string, string> dic = this.getTypeCache();
    string containKey = orgKey + "_" + userKey;
    List<string> keys = new List<string>();
    //Dictionary里面Keys不能用索引直接访问
    foreach (string key in dic.Keys)
    {
    keys.Add(key);

    }
    if (keys.Count > 0)
    {
    foreach (string key in keys)
    {
    if (key.IndexOf(containKey) > 0)
    {
    dic.Remove(key);
    }
    }
    }
    }
    }

    然后,我们可以定义一个工厂类(AbstractCacheFactory)来实现外部的调用

    private static ICache<string, string> _dataAuthCache = null;
    public static AbstractCache<string, string> GetDataAuthCache()
    {
    if (_dataAuthCache == null)
    {
    _dataAuthCache = new DataAuthCache();
    }
    return (AbstractCache<string, string>)_dataAuthCache;
    }

    好了,到这,我们就完成缓存了,很简单吧!

    接下来调用:

    AbstractCache<string, string> dac =AbstractCacheFactory.GetDataAuthCache();
    string cacheHql = dac.GetCache(tpl.EntityName);

    cacheHql就是我们缓存的数据权限查询片段,好了,就分享到这儿了。欢迎大家提出宝贵意见,和分享搞好的方法。

  • 相关阅读:
    map用法详解
    求用1,2,5这三个数不同个数组合的和为100的组合个数
    【雅虎笔试题】两个已经排好序的数组,找中位数
    C++ STL算法系列4---unique , unique_copy函数
    C++ STL算法系列3---求和:accumulate
    C++ STL算法系列2---find ,find_first_of , find_if , adjacent_find的使用
    C/C++面试小知识点
    C语言内存地址基础
    C语言函数指针基础
    C++ STL算法系列1---count函数
  • 原文地址:https://www.cnblogs.com/hsb-comfort/p/Dictionary.html
Copyright © 2020-2023  润新知