SqlSugar本地缓存查询实现方式

发布时间 2023-06-16 17:14:09作者: 你好创造者

有C#的国产ORM SqlSugar 好久了,实在话还不错,不过毕竟是早期产物不能过分要求规范化,有些项目查询语句需要用到缓存,官方是redis,我写了个本地缓存借助ConcurrentBag,因为有的项目禁止过分依赖三方组件,以下是我实现的方法,可供大家参考:

using SqlSugar;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

namespace Common
{
    /// <summary>
    /// SqlSugar本地缓存实现
    /// </summary>
    public class SqlSugarLocalCache : ICacheService
    {
        public static ConcurrentBag<Tuple<string, object, DateTime>> CacheList = new ConcurrentBag<Tuple<string, object, DateTime>>();

        private readonly DateTime now;

        /// <summary>
        /// 最大缓存天数
        /// </summary>
        public int MaxCacheDays { get; set; }

        public SqlSugarLocalCache()
        {
            now = DateTime.Now;
        }

        public void Add<V>(string key, V value)
        {
            ExpiredMonitoring();
            CacheList.Add(new Tuple<string, object, DateTime>(key, value, now.AddDays(3)));
        }

        public void Add<V>(string key, V value, int cacheDurationInSeconds)
        {
            ExpiredMonitoring();
            if (MaxCacheDays > 0)
            {
                int s = GetDaysSeconds(MaxCacheDays);
                if (s < cacheDurationInSeconds) cacheDurationInSeconds = s;
            }
            CacheList.Add(new Tuple<string, object, DateTime>(key, value, now.AddSeconds(cacheDurationInSeconds)));
        }

        public bool ContainsKey<V>(string key)
        {
            ExpiredMonitoring();
            return CacheList.Any(m => m.Item1 == key);
        }

        public V Get<V>(string key)
        {
            ExpiredMonitoring();
            return (V)CacheList.Where(m => m.Item1 == key).FirstOrDefault()?.Item2;
        }

        public IEnumerable<string> GetAllKey<V>()
        {
            ExpiredMonitoring();
            return CacheList.Where(m => m.Item1.StartsWith("SqlSugarDataCache.")).Select(m => m.Item1);
        }

        public V GetOrCreate<V>(string cacheKey, Func<V> create, int cacheDurationInSeconds = int.MaxValue)
        {
            ExpiredMonitoring();

            if (MaxCacheDays > 0)
            {
                int s = GetDaysSeconds(MaxCacheDays);
                if (s < cacheDurationInSeconds) cacheDurationInSeconds = s;
            }

            V result;

            if (ContainsKey<V>(cacheKey))
            {
                result = Get<V>(cacheKey);
                result = result == null ? create() : result;
            }
            else
            {
                result = create();
                Add(cacheKey, result, cacheDurationInSeconds);
            }

            return result;
        }

        public void Remove<V>(string key)
        {
            ExpiredMonitoring();
            if (ContainsKey<V>(key))
            {
                var result = CacheList.Where(m => m.Item1 == key).FirstOrDefault();
                CacheList.TryTake(out result);
            }
        }

        /// <summary>
        /// 过期监听
        /// </summary>
        private void ExpiredMonitoring()
        {
            var expList = CacheList.Where(m => m.Item3 < now).ToList();
            int l = expList.Count;
            for (int i = 0; i < l; i++)
            {
                var item = expList[i];
                CacheList.TryTake(out item);
            }
        }

        /// <summary>
        /// 获取指定天数秒数
        /// </summary>
        /// <param name="days">指定天数</param>
        /// <returns></returns>
        private static int GetDaysSeconds(int days)
        {
            return 60 * 60 * 24 * days;
        }
    }
}