diff --git a/src/SJZY.Track.Application/Caching/BasicCacheForPeriodicRefresh.cs b/src/SJZY.Track.Application/Caching/BasicCacheForPeriodicRefresh.cs
new file mode 100644
index 00000000..609bf823
--- /dev/null
+++ b/src/SJZY.Track.Application/Caching/BasicCacheForPeriodicRefresh.cs
@@ -0,0 +1,515 @@
+using System.Collections.Concurrent;
+using FreeRedis;
+using Microsoft.Extensions.Caching.Memory;
+using Newtonsoft.Json;
+using SJZY.Track.Domain.Extensions;
+
+namespace SJZY.Track.Application.Caching;
+
+///
+/// 容忍短暂的数据不一致,固定周期内强制刷新(本地缓存过期时强制刷新)
+/// 适合存字典数据,
+/// 注意:缓存过多的大对象有可能OOM,尽量避免
+/// 注意:redis内数据只新增/修改,不删!!!
+///
+public abstract class BasicCacheForPeriodicRefresh
+ where TKey : notnull
+ where TValue : class
+{
+ private readonly IMemoryCache _memoryCache;
+ private readonly IRedisClient _redis;
+
+ protected BasicCacheForPeriodicRefresh(IRedisClient redis, IMemoryCache? memoryCache = null)
+ {
+ _redis = redis;
+ _memoryCache = memoryCache ?? new MemoryCache(new MemoryCacheOptions
+ {
+ CompactionPercentage = 0.75
+ });
+ }
+
+ protected abstract string BuildRedisKey(TKey key);
+ protected abstract TimeSpan RedisExpire { get; }
+ protected virtual TimeSpan LocalExpire => RedisExpire.Divide(2);
+ protected abstract TimeSpan MissingKeySetNullRedisExpire { get; }
+ protected virtual TimeSpan MissingKeySetNullLocalExpire => MissingKeySetNullRedisExpire.Divide(2);
+
+ protected abstract ValueTask LoadAsync(TKey key);
+ protected abstract ValueTask> LoadAsync(HashSet keys);
+
+ private const string ConcurrentKey = "ConcurrentKey";
+
+ private readonly ConcurrentDictionary _semaphoreDict = new()
+ {
+ [ConcurrentKey] = new SemaphoreSlim(10, 10)
+ };
+
+ ///
+ /// 安全获取缓存
+ /// 同一个key最多允许并行1个访问
+ ///
+ ///
+ ///
+ public async ValueTask SafeGetAsync(TKey key)
+ {
+ var k = key.ToString()!;
+ var semaphore = _semaphoreDict.GetOrAdd(k, _ => new SemaphoreSlim(1, 1));
+ await semaphore.WaitAsync();
+ try
+ {
+ return await GetAsync(key);
+ }
+ finally
+ {
+ semaphore.Release();
+ _semaphoreDict.TryRemove(k, out _);
+ }
+ }
+
+ ///
+ /// 批量获取缓存
+ /// 同时最多同时允许10个并发批量缓存访问
+ ///
+ ///
+ ///
+ public async ValueTask> SafeGetBatchAsync(HashSet keys)
+ {
+ var semaphore = _semaphoreDict[ConcurrentKey];
+ await semaphore.WaitAsync();
+ try
+ {
+ return await GetBatchAsync(keys);
+ }
+ finally
+ {
+ semaphore.Release();
+ }
+ }
+
+ private async ValueTask GetAsync(TKey key)
+ {
+ // 1.LocalLoad
+ var localEntry = GetLocal(key);
+ if (localEntry != null)
+ {
+ // 1.1 expire refresh for db
+ if (localEntry.HasExpire)
+ return await RefreshForDbAsync(key);
+
+ // 1.2 not expire return
+ return localEntry.Data;
+ }
+
+ // 2.RedisLoad
+ var redisEntry = await GetRedisAsync(key);
+ if (redisEntry != null)
+ {
+ SetLocal(key, redisEntry, redisEntry.Data == null
+ ? MissingKeySetNullLocalExpire
+ : LocalExpire
+ );
+ return redisEntry.Data;
+ }
+
+ // 3.DbLoad
+ var dbValue = await LoadAsync(key);
+ if (dbValue != null)
+ {
+ SetLocal(key, CacheEntry.Create(dbValue, LocalExpire));
+ await SetRedisAsync(key, dbValue, LocalExpire);
+ return dbValue;
+ }
+
+ // db miss set null short expire
+ SetLocal(key, CacheEntry.CreateEmpty(MissingKeySetNullLocalExpire));
+ await SetRedisAsync(key, null, cacheExpire: MissingKeySetNullRedisExpire);
+
+ return null;
+ }
+
+ private async ValueTask RefreshForDbAsync(TKey key)
+ {
+ // 1.从数据库加载
+ var dbValue = await LoadAsync(key);
+ if (dbValue != null)
+ {
+ SetLocal(key, CacheEntry.Create(dbValue, LocalExpire));
+ await SetRedisAsync(key, dbValue);
+ }
+
+ // 2.db加载不到,触发兜底
+ var redisValue = await GetRedisAsync(key);
+ if (redisValue != null)
+ {
+ // 2.1 设置本地缓存,如果兜底的值为null则需要设置较短过期时间
+ SetLocal(key, redisValue, redisValue.Data == null
+ ? MissingKeySetNullLocalExpire
+ : LocalExpire
+ );
+
+ return redisValue.Data;
+ }
+
+ // 3.触发兜底也失败了,设置本地缓存和redis
+ SetLocal(key, CacheEntry.CreateEmpty(MissingKeySetNullLocalExpire));
+ await SetRedisAsync(key, null, cacheExpire: MissingKeySetNullRedisExpire);
+ return null;
+ }
+
+ private async ValueTask> OnlyLocalMissKeyAsync(List keys)
+ {
+ var resultDict = new Dictionary();
+
+ // 1.redis加载
+ var redisMissKeys = new HashSet();
+ var localMissKeyArray = keys.ToArray();
+ var redisValues = await MGetRedisAsync(keys);
+ for (var i = 0; i < redisValues.Length; i++)
+ {
+ var entry = redisValues[i];
+ if (entry == null)
+ {
+ redisMissKeys.Add(localMissKeyArray[i]);
+ continue;
+ }
+
+ if (entry.Data != null)
+ resultDict.Add(localMissKeyArray[i], entry.Data);
+
+ // 设置本地缓存,空值和非空值过期时间不同
+ SetLocal(localMissKeyArray[i], entry, entry.Data == null
+ ? MissingKeySetNullLocalExpire
+ : LocalExpire
+ );
+ }
+
+ if (redisMissKeys.Count == 0)
+ return resultDict;
+
+ // 2.db加载
+ var dbValueDict = await LoadAsync(redisMissKeys);
+ if (dbValueDict.Count > 0)
+ {
+ foreach (var kv in dbValueDict)
+ resultDict.Add(kv.Key, kv.Value);
+
+ MSetLocal(dbValueDict!, LocalExpire);
+ await MSetRedisAsync(dbValueDict!, cacheExpire: RedisExpire);
+ }
+
+ if (dbValueDict.Count == redisMissKeys.Count)
+ return resultDict;
+
+ // 3.db加载失败,设置null值
+ var dbMissKeys = redisMissKeys.Except(dbValueDict.Keys).ToDictionary(x => x, _ => CacheEntry.CreateEmpty(MissingKeySetNullLocalExpire));
+ MSetLocal(dbMissKeys, MissingKeySetNullLocalExpire);
+ await MSetRedisAsync(dbMissKeys, cacheExpire: MissingKeySetNullRedisExpire);
+
+ return resultDict;
+ }
+
+ private async ValueTask> OnlyLocalExpireKeyAsync(List keys)
+ {
+ var resultDict = new Dictionary();
+
+ // 1.DbLoad
+ var dbValueDict = await LoadAsync(keys.ToHashSet());
+ foreach (var kv in dbValueDict)
+ resultDict.Add(kv.Key, kv.Value);
+
+ if (dbValueDict.Count == keys.Count)
+ {
+ // 刷新本地缓存,还有redis缓存
+ MSetLocal(dbValueDict!, LocalExpire);
+ await MSetRedisAsync(dbValueDict!, RedisExpire);
+ return resultDict;
+ }
+
+
+ var nullValueSetDict = new Dictionary();
+
+ // 2.Redis兜底
+ var dbMissKeys = keys.Except(dbValueDict.Keys).ToList();
+ var dbMissKeyArray = dbMissKeys.ToArray();
+ var redisValues = await MGetRedisAsync(dbMissKeys);
+ for (var i = 0; i < redisValues.Length; i++)
+ {
+ var entry = redisValues[i];
+ if (entry == null) // 触发兜底也失败了
+ {
+ nullValueSetDict.Add(dbMissKeyArray[i], CacheEntry.CreateEmpty(MissingKeySetNullLocalExpire));
+ continue;
+ }
+
+ if (entry.Data != null)
+ resultDict.Add(dbMissKeyArray[i], entry.Data);
+
+ // 加载成功设置本地缓存
+ SetLocal(dbMissKeyArray[i], entry, entry.Data == null
+ ? MissingKeySetNullLocalExpire
+ : LocalExpire
+ );
+ }
+
+ // 缓存null值防止缓存穿透
+ if (nullValueSetDict.Count > 0)
+ {
+ MSetLocal(nullValueSetDict, MissingKeySetNullLocalExpire);
+ await MSetRedisAsync(nullValueSetDict, cacheExpire: MissingKeySetNullRedisExpire);
+ }
+
+ return resultDict;
+ }
+
+ private async ValueTask> GetBatchAsync(HashSet keys)
+ {
+ if (keys.Count == 0) return Empty.Dict;
+
+ // 1.LocalLoad
+ var localEntries = MGetLocal(keys);
+
+ // 选出过期的key和未命中的key
+ var expireKeys = localEntries.Where(x => x.Value.HasExpire).Select(x => x.Key).ToList();
+ var localMissKeys = keys.Except(localEntries.Keys).ToList();
+
+ // 选出未过期并且不为空的值作为返回的基本组成
+ var resultDict = localEntries.Where(x => !x.Value.HasExpire && x.Value.Data != null).ToDictionary(x => x.Key, y => y.Value.Data!);
+
+ // 不存在过期的也不存在未命中的直接返回即可
+ if (expireKeys.Count == 0 && localMissKeys.Count == 0)
+ {
+ return resultDict;
+ }
+
+ // 只存在未命中的key
+ if (expireKeys.Count == 0 && localMissKeys.Count > 0)
+ {
+ var loadDict = await OnlyLocalMissKeyAsync(localMissKeys);
+ foreach (var kv in loadDict)
+ resultDict.Add(kv.Key, kv.Value);
+ return resultDict;
+ }
+
+ // 只存在过期的key
+ if (expireKeys.Count > 0 && localMissKeys.Count == 0)
+ {
+ var loadDict = await OnlyLocalExpireKeyAsync(expireKeys);
+ foreach (var kv in loadDict)
+ resultDict.Add(kv.Key, kv.Value);
+ return resultDict;
+ }
+
+ // 既存在未命中的key,也存在过期的key
+ // 2.RedisLoad 仅对missKeys尝试进行redis加载
+ var redisMissKeys = new List();
+ var localMissKeyArray = localMissKeys.ToArray();
+ var redisValues = await MGetRedisAsync(localMissKeys);
+ for (var i = 0; i < redisValues.Length; i++)
+ {
+ var entry = redisValues[i];
+ if (entry == null)
+ {
+ redisMissKeys.Add(localMissKeyArray[i]);
+ continue;
+ }
+
+ if (entry.Data != null)
+ resultDict.Add(localMissKeyArray[i], entry.Data);
+
+ // 加载成功设置本地缓存
+ SetLocal(localMissKeyArray[i], entry, entry.Data == null
+ ? MissingKeySetNullLocalExpire
+ : LocalExpire
+ );
+ }
+
+ // 3.DbLoad redis未命中和过期的key
+ var unionKeys = new HashSet(redisMissKeys.Count + expireKeys.Count);
+ unionKeys.UnionWith(redisMissKeys);
+ unionKeys.UnionWith(expireKeys);
+ var dbValueDict = await LoadAsync(unionKeys);
+
+ // 比较新鲜的数据,设置redis缓存+本地缓存
+ if (dbValueDict.Count > 0)
+ {
+ foreach (var kv in dbValueDict)
+ resultDict.Add(kv.Key, kv.Value);
+
+ MSetLocal(dbValueDict!, LocalExpire);
+ await MSetRedisAsync(dbValueDict!, RedisExpire);
+ }
+
+ // 全部加载成功
+ if (dbValueDict.Count == unionKeys.Count)
+ {
+ return resultDict;
+ }
+
+ var nullValueSetDict = new Dictionary();
+
+ // 本地未命中的key,从redis和db加载都失败,稍后将这些key设置一个null值,以防缓存穿透
+ var dbMissingKeys = redisMissKeys.Except(dbValueDict.Keys).ToList();
+ if (dbMissingKeys.Count > 0)
+ {
+ foreach (var key in dbMissingKeys)
+ nullValueSetDict.Add(key, CacheEntry.CreateEmpty(MissingKeySetNullLocalExpire));
+ }
+
+ // 本地过期的key,从db加载失败,触发兜底策略,兜底也失败则将这些key设置一个null值,以防缓存穿透
+ var expireKeysNotInDb = expireKeys.Except(dbValueDict.Keys).ToList();
+ if (expireKeysNotInDb.Count > 0)
+ {
+ redisValues = await MGetRedisAsync(expireKeysNotInDb);
+ for (var i = 0; i < redisValues.Length; i++)
+ {
+ var entry = redisValues[i];
+ if (entry == null) // 触发兜底也失败了
+ {
+ nullValueSetDict.Add(expireKeysNotInDb[i], CacheEntry.CreateEmpty(MissingKeySetNullLocalExpire));
+ continue;
+ }
+
+ if (entry.Data != null)
+ resultDict.Add(localMissKeyArray[i], entry.Data);
+
+ // 加载成功设置本地缓存
+ SetLocal(localMissKeyArray[i], entry, entry.Data == null
+ ? MissingKeySetNullLocalExpire
+ : LocalExpire
+ );
+ }
+ }
+
+ // 缓存null值防止缓存穿透
+ if (nullValueSetDict.Count > 0)
+ {
+ MSetLocal(nullValueSetDict, MissingKeySetNullLocalExpire);
+ await MSetRedisAsync(nullValueSetDict, MissingKeySetNullRedisExpire);
+ }
+
+ return resultDict;
+ }
+
+ #region 缓存操作方法
+
+ private async ValueTask GetRedisAsync(TKey key)
+ {
+ return await _redis.GetAsync(BuildRedisKey(key));
+ }
+
+ private async ValueTask MGetRedisAsync(List keys)
+ {
+ var redisKeys = keys.Select(BuildRedisKey).ToArray();
+ return await _redis.MGetAsync(redisKeys);
+ }
+
+ private CacheEntry? GetLocal(TKey key)
+ {
+ return _memoryCache.Get(key);
+ }
+
+ private Dictionary MGetLocal(HashSet keys)
+ {
+ var result = new Dictionary();
+ foreach (var k in keys)
+ {
+ if (_memoryCache.TryGetValue(k, out var entry))
+ result.Add(k, entry!);
+ }
+
+ return result;
+ }
+
+ private Task MSetRedisAsync(Dictionary dict, TimeSpan? expire = null, TimeSpan? cacheExpire = null)
+ {
+ return MSetRedisAsync(dict.ToDictionary(x => x.Key, y => CacheEntry.Create(y.Value, expire)), cacheExpire);
+ }
+
+ private async Task MSetRedisAsync(Dictionary dict, TimeSpan? cacheExpire = null)
+ {
+ var setDict = dict.ToDictionary(x => BuildRedisKey(x.Key), y => y.Value);
+ await _redis.MSetAsync(setDict);
+
+ if (!cacheExpire.HasValue || cacheExpire.Value.TotalSeconds <= 0.0d) return;
+ // 设置过期时间
+ foreach (var k in setDict.Keys)
+ await _redis.ExpireAsync(k, cacheExpire.Value);
+ }
+
+ private Task SetRedisAsync(TKey key, TValue? value, TimeSpan? expire = null, TimeSpan? cacheExpire = null)
+ {
+ cacheExpire = cacheExpire?.TotalSeconds > 0.0 ? cacheExpire : TimeSpan.FromSeconds(-1);
+ return _redis.SetAsync(BuildRedisKey(key), CacheEntry.Create(value, expire), cacheExpire.Value);
+ }
+
+ private void MSetLocal(Dictionary dict, TimeSpan? expire = null, TimeSpan? cacheExpire = null)
+ {
+ MSetLocal(dict.ToDictionary(x => x.Key, y => CacheEntry.Create(y.Value, expire)), null, cacheExpire);
+ }
+
+ private void MSetLocal(Dictionary dict, TimeSpan? expire = null, TimeSpan? cacheExpire = null)
+ {
+ foreach (var kv in dict)
+ SetLocal(kv.Key, kv.Value, expire, cacheExpire);
+ }
+
+ private void SetLocal(TKey key, TValue? value, TimeSpan? expire = null, TimeSpan? cacheExpire = null)
+ {
+ SetLocal(key, CacheEntry.Create(value, expire), null, cacheExpire);
+ }
+
+ private void SetLocal(TKey key, CacheEntry entry, TimeSpan? expire = null, TimeSpan? cacheExpire = null)
+ {
+ if (expire.HasValue)
+ {
+ entry.SetExpire(expire.Value);
+ }
+
+ _memoryCache.Set(key, entry, cacheExpire?.TotalSeconds > 0.0d
+ ? new MemoryCacheEntryOptions
+ {
+ AbsoluteExpirationRelativeToNow = cacheExpire
+ }
+ : null
+ );
+ }
+
+ #endregion
+
+ private class CacheEntry
+ {
+ private static readonly DateTime NoExpire = DateTime.MaxValue;
+ public TValue? Data { get; set; }
+
+ [System.Text.Json.Serialization.JsonIgnore]
+ [JsonIgnore]
+ public DateTime Expire { get; set; }
+
+ [System.Text.Json.Serialization.JsonIgnore]
+ [JsonIgnore]
+ public bool HasExpire => Expire < DateTime.Now;
+
+ public static CacheEntry Create(TValue? data, TimeSpan? expire = null)
+ {
+ return new CacheEntry
+ {
+ Data = data,
+ Expire = expire.HasValue ? DateTime.Now.Add(expire.Value) : NoExpire
+ };
+ }
+
+ public static CacheEntry CreateEmpty(TimeSpan expire)
+ {
+ return new CacheEntry
+ {
+ Data = null,
+ Expire = DateTime.Now.Add(expire)
+ };
+ }
+
+ public void SetExpire(TimeSpan expire)
+ {
+ Expire = DateTime.Now.Add(expire);
+ }
+ }
+}
diff --git a/src/SJZY.Track.Application/Caching/CustomAbbreviationDictCache.cs b/src/SJZY.Track.Application/Caching/CustomAbbreviationDictCache.cs
new file mode 100644
index 00000000..fb4a9c06
--- /dev/null
+++ b/src/SJZY.Track.Application/Caching/CustomAbbreviationDictCache.cs
@@ -0,0 +1,45 @@
+using SJZY.Expand.ABP.Core;
+using SJZY.Track.Domain.Extensions;
+using SJZY.Track.Domain.Queries;
+using Volo.Abp.DependencyInjection;
+
+namespace SJZY.Track.Application.Caching;
+
+///
+/// 客户id简称缓存
+///
+public class CustomAbbreviationDictCache : BasicCacheForPeriodicRefresh, ISingletonDependency
+{
+ private readonly IVExternalSubjectQueries _vExternalSubjectQueries;
+
+ public CustomAbbreviationDictCache(IVExternalSubjectQueries vExternalSubjectQueries) : base(RedisHelper.Client)
+ {
+ _vExternalSubjectQueries = vExternalSubjectQueries;
+ }
+
+ protected override string BuildRedisKey(int key) => $"{GlobalConst.TrackDataDictKeyPrefix}:CustomAbbreviation:{key}";
+
+ protected override TimeSpan RedisExpire => TimeSpan.FromSeconds(-1); // 设置缓存不过期,指定id客户被删除时仍能兜底提供简称
+ protected override TimeSpan LocalExpire => TimeSpan.FromMinutes(5); // 本地缓存5分钟过期后在次请求会刷新数据
+ protected override TimeSpan MissingKeySetNullRedisExpire => TimeSpan.FromMinutes(1); // 缓存不存在时设置redisNull
+
+ protected override async ValueTask LoadAsync(int key)
+ {
+ if (key == 0) return null;
+ return await _vExternalSubjectQueries.GetFirstAsync(x => x.Id == key, x => x.Abbreviation);
+ }
+
+ protected override async ValueTask> LoadAsync(HashSet keys)
+ {
+ if (keys.Count == 0) return Empty.Dict;
+ var result = await _vExternalSubjectQueries.GetListAsync(x => keys.Contains(x.Id), x => new
+ {
+ x.Id,
+ x.Abbreviation
+ });
+
+ return result.Count == 0
+ ? Empty.Dict
+ : result.ToDictionary(x => x.Id, y => y.Abbreviation);
+ }
+}
diff --git a/src/SJZY.Track.Application/Caching/SystemCnNameDictCache.cs b/src/SJZY.Track.Application/Caching/SystemCnNameDictCache.cs
new file mode 100644
index 00000000..3fedf83f
--- /dev/null
+++ b/src/SJZY.Track.Application/Caching/SystemCnNameDictCache.cs
@@ -0,0 +1,46 @@
+using SJZY.Expand.ABP.Core;
+using SJZY.Track.Domain.Extensions;
+using SJZY.Track.Domain.Queries;
+using Volo.Abp.DependencyInjection;
+
+namespace SJZY.Track.Application.Caching;
+
+///
+/// 系统id中文名称字典缓存
+///
+public class SystemCnNameDictCache : BasicCacheForPeriodicRefresh, ISingletonDependency
+{
+ private readonly IVSystemQueries _vSystemQueries;
+
+ public SystemCnNameDictCache(IVSystemQueries vSystemQueries) : base(RedisHelper.Client)
+ {
+ _vSystemQueries = vSystemQueries;
+ }
+
+ protected override string BuildRedisKey(int key) => $"{GlobalConst.TrackDataDictKeyPrefix}:SystemCnName:{key}";
+
+ protected override TimeSpan RedisExpire => TimeSpan.FromSeconds(-1); // 设置缓存不过期,指定id系统被删除时仍能兜底提供系统中文名
+ protected override TimeSpan LocalExpire => TimeSpan.FromMinutes(10); // 本地缓存10分钟过期后在次请求会刷新数据
+ protected override TimeSpan MissingKeySetNullRedisExpire => TimeSpan.FromMinutes(1); // 缓存不存在时设置redisNull
+
+ protected override async ValueTask LoadAsync(int key)
+ {
+ if (key == 0) return null;
+ return await _vSystemQueries.GetFirstAsync(x => x.Id == key, x => x.CnName);
+ }
+
+ protected override async ValueTask> LoadAsync(HashSet keys)
+ {
+ if (keys.Count == 0) return Empty.Dict;
+
+ var result = await _vSystemQueries.GetListAsync(x => keys.Contains(x.Id), x => new
+ {
+ x.Id,
+ x.CnName
+ });
+
+ return result.Count == 0
+ ? Empty.Dict
+ : result.ToDictionary(x => x.Id, y => y.CnName);
+ }
+}
diff --git a/src/SJZY.Track.Application/Caching/TrackStatusNameDictCache.cs b/src/SJZY.Track.Application/Caching/TrackStatusNameDictCache.cs
new file mode 100644
index 00000000..9fae9972
--- /dev/null
+++ b/src/SJZY.Track.Application/Caching/TrackStatusNameDictCache.cs
@@ -0,0 +1,45 @@
+using SJZY.Expand.ABP.Core;
+using SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
+using SJZY.Track.Domain.Extensions;
+using Volo.Abp.DependencyInjection;
+
+namespace SJZY.Track.Application.Caching;
+
+///
+/// 轨迹状态id名称字典缓存
+///
+public class TrackStatusNameDictCache : BasicCacheForPeriodicRefresh, ISingletonDependency
+{
+ private readonly ITrackStatusRepository _trackStatusRepository;
+
+ public TrackStatusNameDictCache(ITrackStatusRepository trackStatusRepository) : base(RedisHelper.Client)
+ {
+ _trackStatusRepository = trackStatusRepository;
+ }
+
+ protected override string BuildRedisKey(int key) => $"{GlobalConst.TrackDataDictKeyPrefix}:TrackStatus:{key}";
+
+ protected override TimeSpan RedisExpire => TimeSpan.FromSeconds(-1); // 设置缓存不过期,指定id状态删除时仍能提供兜底状态名称
+ protected override TimeSpan LocalExpire => TimeSpan.FromMinutes(5); // 本地缓存5分钟过期后在次请求会刷新数据
+ protected override TimeSpan MissingKeySetNullRedisExpire => TimeSpan.FromMinutes(1); // 缓存不存在时设置redisNull
+
+ protected override async ValueTask LoadAsync(int key)
+ {
+ if (key == 0) return null;
+ return await _trackStatusRepository.GetFirstAsync(x => x.Id == key, x => x.Status);
+ }
+
+ protected override async ValueTask> LoadAsync(HashSet keys)
+ {
+ if (keys.Count == 0) return Empty.Dict;
+ var result = await _trackStatusRepository.GetListAsync(x => keys.Contains(x.Id), x => new
+ {
+ x.Id,
+ x.Status
+ });
+
+ return result.Count == 0
+ ? Empty.Dict
+ : result.ToDictionary(x => x.Id, y => y.Status);
+ }
+}
diff --git a/src/SJZY.Track.Application/Services/Warning/CompleteWarningService.cs b/src/SJZY.Track.Application/Services/Warning/CompleteWarningService.cs
index 07a6140b..bb30224c 100644
--- a/src/SJZY.Track.Application/Services/Warning/CompleteWarningService.cs
+++ b/src/SJZY.Track.Application/Services/Warning/CompleteWarningService.cs
@@ -1,5 +1,5 @@
-using Nest;
using SJZY.Expand.ABP.Core.PublicMethords;
+using SJZY.Track.Application.Caching;
using SJZY.Track.Application.Contract.Dtos.Warning;
using SJZY.Track.Application.Contract.Dtos.Warning.Complete;
using SJZY.Track.Application.Contract.Dtos.Warning.Return;
@@ -8,13 +8,11 @@ using SJZY.Track.Application.Services.Warning.Handlers;
using SJZY.Track.Application.Services.Warning.Model;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
-using SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
using SJZY.Track.Domain.Aggregates.WarningAggregate;
using SJZY.Track.Domain.Aggregates.WarningAggregate.Complete;
using SJZY.Track.Domain.Dtos.Warning;
using SJZY.Track.Domain.Enums;
using SJZY.Track.Domain.Extensions;
-using SJZY.Track.Domain.Queries;
namespace SJZY.Track.Application.Services.Warning;
@@ -26,26 +24,36 @@ namespace SJZY.Track.Application.Services.Warning;
public class CompleteWarningService : ApplicationService
{
private readonly IOrderRepository _orderRepository;
- private readonly IVExternalSubjectQueries _vExternalSubjectQueries;
- private readonly IVSystemQueries _vSystemQueries;
private readonly IWarningRuleRepository _warningRuleRepository;
private readonly IWarningDetailsEsRepository _warningDetailsEsRepository;
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
private readonly ICompleteWarningHandler _completeWarningHandler;
- private readonly ITrackStatusRepository _trackStatusRepository;
+ private readonly TrackStatusNameDictCache _trackStatusNameDictCache;
+ private readonly CustomAbbreviationDictCache _customAbbreviationDictCache;
+ private readonly SystemCnNameDictCache _systemCnNameDictCache;
- public CompleteWarningService(IWarningRuleRepository warningRuleRepository, IWarningDetailsEsRepository warningDetailsEsRepository, ITrackDetailsEsRepository trackDetailsEsRepository, ICompleteWarningHandler completeWarningHandler, ITrackStatusRepository trackStatusRepository, IOrderRepository orderRepository, IVSystemQueries vSystemQueries, IVExternalSubjectQueries vExternalSubjectQueries)
+ public CompleteWarningService(
+ IOrderRepository orderRepository,
+ IWarningRuleRepository warningRuleRepository,
+ IWarningDetailsEsRepository warningDetailsEsRepository,
+ ITrackDetailsEsRepository trackDetailsEsRepository,
+ ICompleteWarningHandler completeWarningHandler,
+ TrackStatusNameDictCache trackStatusNameDictCache,
+ CustomAbbreviationDictCache customAbbreviationDictCache,
+ SystemCnNameDictCache systemCnNameDictCache
+ )
{
+ _orderRepository = orderRepository;
_warningRuleRepository = warningRuleRepository;
_warningDetailsEsRepository = warningDetailsEsRepository;
_trackDetailsEsRepository = trackDetailsEsRepository;
_completeWarningHandler = completeWarningHandler;
- _trackStatusRepository = trackStatusRepository;
- _orderRepository = orderRepository;
- _vSystemQueries = vSystemQueries;
- _vExternalSubjectQueries = vExternalSubjectQueries;
+ _trackStatusNameDictCache = trackStatusNameDictCache;
+ _customAbbreviationDictCache = customAbbreviationDictCache;
+ _systemCnNameDictCache = systemCnNameDictCache;
}
+
///
/// 获取完整预警规则列表
///
@@ -58,7 +66,6 @@ public class CompleteWarningService : ApplicationService
if (result.Count == 0)
return new UnifyResultDto>(true, new List());
- // todo:缓存优化
var trackStatusIds = result
.SelectMany(x =>
{
@@ -72,13 +79,9 @@ public class CompleteWarningService : ApplicationService
return requireStatusIds.SelectMany(y => y);
}).ToHashSet();
- var trackStatusDict = (await _trackStatusRepository.GetListAsync(x => trackStatusIds.Contains(x.Id), x => new
- {
- x.Id,
- x.Status
- })).ToDictionary(x => x.Id, y => y.Status);
-
- // 查订单类型映射
+ // 查轨迹状态名称字典
+ var trackStatusDict = await _trackStatusNameDictCache.SafeGetBatchAsync(trackStatusIds);
+ // 查订单类型字典
var orderTypeDict = await _orderRepository.GetTrackOrderTypeDictAsync();
var map = result.Select(x => new CompleteWarningRuleItemDto
@@ -136,40 +139,27 @@ public class CompleteWarningService : ApplicationService
result.Pagination.Total);
}
- // todo:缓存优化
+
+ // 订单类型名称字典
+ var orderTypeDict = await _orderRepository.GetTrackOrderTypeDictAsync();
+
var trackStatusIds = result.List
.SelectMany(x => x.GetMissingTrackStatusIdGroups().SelectMany(y => y))
.ToHashSet();
- var trackStatusDict = (await _trackStatusRepository.GetListAsync(x => trackStatusIds.Contains(x.Id), x => new
- {
- x.Id,
- x.Status
- })).ToDictionary(x => x.Id, y => y.Status);
+ // 轨迹状态名称字典
+ var trackStatusDict = await _trackStatusNameDictCache.SafeGetBatchAsync(trackStatusIds);
+
+ // 客户id简称字典
+ var customIds = result.List.Select(x => x.CustomId).ToHashSet();
+ var customDict = await _customAbbreviationDictCache.SafeGetBatchAsync(customIds);
+ // 子系统id中文名字典
+ var subSystemIds = result.List.Select(x => x.SubSystemId).ToHashSet();
+ var subSystemDict = await _systemCnNameDictCache.SafeGetBatchAsync(subSystemIds);
// 查最新轨迹(创建时间)
var orderIds = result.List.Select(x => x.OrderId).ToHashSet();
var orderIdTrackDict = await _trackDetailsEsRepository.GetLatestDictAsync(orderIds);
- // todo:缓存优化
- // 订单类型
- var orderTypeDict = await _orderRepository.GetTrackOrderTypeDictAsync();
- // 客户简称
- var customIds = result.List.Select(x => x.CustomId).ToHashSet();
- var customDict = (await _vExternalSubjectQueries
- .GetListAsync(x => customIds.Contains(x.Id), x => new
- {
- x.Id,
- x.Abbreviation
- })).ToDictionary(x => x.Id, x => x.Abbreviation);
- // 子系统
- var subSystemIds = result.List.Select(x => x.SubSystemId).ToHashSet();
- var subSystemDict = (await _vSystemQueries
- .GetListAsync(x => subSystemIds.Contains(x.Id), x => new
- {
- x.Id,
- x.CnName
- })).ToDictionary(x => x.Id, x => x.CnName);
-
var map = result.List.Select(x =>
{
var orderIdTrack = orderIdTrackDict.GetValueOrDefault(x.OrderId);
diff --git a/src/SJZY.Track.Application/Services/Warning/ReturnWarningService.cs b/src/SJZY.Track.Application/Services/Warning/ReturnWarningService.cs
index da5c51b9..8496435d 100644
--- a/src/SJZY.Track.Application/Services/Warning/ReturnWarningService.cs
+++ b/src/SJZY.Track.Application/Services/Warning/ReturnWarningService.cs
@@ -1,5 +1,6 @@
using DotNetCore.CAP;
using SJZY.Expand.ABP.Core.PublicMethords;
+using SJZY.Track.Application.Caching;
using SJZY.Track.Application.Contract.Dtos.Warning;
using SJZY.Track.Application.Contract.Dtos.Warning.Return;
using SJZY.Track.Application.Contract.Events;
@@ -7,7 +8,6 @@ using SJZY.Track.Application.Helpers;
using SJZY.Track.Application.Services.Warning.Handlers;
using SJZY.Track.Application.Services.Warning.Model;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
-using SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
using SJZY.Track.Domain.Aggregates.WarningAggregate;
using SJZY.Track.Domain.Dtos.Warning;
using SJZY.Track.Domain.Enums;
@@ -25,27 +25,39 @@ namespace SJZY.Track.Application.Services.Warning;
public class ReturnWarningService : ApplicationService
{
private readonly IOrderRepository _orderRepository;
- private readonly IVExternalSubjectQueries _vExternalSubjectQueries;
private readonly IVSystemQueries _vSystemQueries;
private readonly IReturnWarningHandler _returnWarningHandler;
private readonly IWarningRuleRepository _warningRuleRepository;
private readonly IWarningDetailsEsRepository _warningDetailsEsRepository;
- private readonly ITrackStatusRepository _trackStatusRepository;
private readonly ICapPublisher _capPublisher;
private readonly IHttpClientProxy _requestCurrentUserService;
+ private readonly TrackStatusNameDictCache _trackStatusNameDictCache;
+ private readonly CustomAbbreviationDictCache _customAbbreviationDictCache;
+ private readonly SystemCnNameDictCache _systemCnNameDictCache;
-
- public ReturnWarningService(IWarningRuleRepository warningRuleRepository, IWarningDetailsEsRepository warningDetailsEsRepository, IReturnWarningHandler returnWarningHandler, ITrackStatusRepository trackStatusRepository, IOrderRepository orderRepository, IVExternalSubjectQueries vExternalSubjectQueries, IVSystemQueries vSystemQueries, ICapPublisher capPublisher, IHttpClientProxy requestCurrentUserService)
+ public ReturnWarningService(
+ IOrderRepository orderRepository,
+ IVSystemQueries vSystemQueries,
+ IReturnWarningHandler returnWarningHandler,
+ IWarningRuleRepository warningRuleRepository,
+ IWarningDetailsEsRepository warningDetailsEsRepository,
+ ICapPublisher capPublisher,
+ IHttpClientProxy requestCurrentUserService,
+ TrackStatusNameDictCache trackStatusNameDictCache,
+ CustomAbbreviationDictCache customAbbreviationDictCache,
+ SystemCnNameDictCache systemCnNameDictCache
+ )
{
+ _orderRepository = orderRepository;
+ _vSystemQueries = vSystemQueries;
+ _returnWarningHandler = returnWarningHandler;
_warningRuleRepository = warningRuleRepository;
_warningDetailsEsRepository = warningDetailsEsRepository;
- _returnWarningHandler = returnWarningHandler;
- _trackStatusRepository = trackStatusRepository;
- _orderRepository = orderRepository;
- _vExternalSubjectQueries = vExternalSubjectQueries;
- _vSystemQueries = vSystemQueries;
_capPublisher = capPublisher;
_requestCurrentUserService = requestCurrentUserService;
+ _trackStatusNameDictCache = trackStatusNameDictCache;
+ _customAbbreviationDictCache = customAbbreviationDictCache;
+ _systemCnNameDictCache = systemCnNameDictCache;
}
///
@@ -61,16 +73,10 @@ public class ReturnWarningService : ApplicationService
if (result.Count == 0)
return new UnifyResultDto>(true, new List());
- // todo:缓存优化
var trackStatusIds = result
.SelectMany(x => x.TrackStatusIds.Split(',').Select(int.Parse))
.ToHashSet();
- var trackStatusDict = (await _trackStatusRepository.GetListAsync(x => trackStatusIds.Contains(x.Id), x => new
- {
- x.Id,
- x.Status
- })).ToDictionary(x => x.Id, y => y.Status);
-
+ var trackStatusDict = await _trackStatusNameDictCache.SafeGetBatchAsync(trackStatusIds);
var map = result.Select(x => new ReturnWarningRuleItemDto
{
@@ -114,25 +120,14 @@ public class ReturnWarningService : ApplicationService
result.Pagination.Total);
}
- // todo:缓存优化
- // 订单类型
+ // 订单类型名称字典
var orderTypeDict = await _orderRepository.GetTrackOrderTypeDictAsync();
- // 客户简称
+ // 客户id简称字典
var customIds = result.List.Select(x => x.CustomId).ToHashSet();
- var customDict = (await _vExternalSubjectQueries
- .GetListAsync(x => customIds.Contains(x.Id), x => new
- {
- x.Id,
- x.Abbreviation
- })).ToDictionary(x => x.Id, x => x.Abbreviation);
- // 子系统
+ var customDict = await _customAbbreviationDictCache.SafeGetBatchAsync(customIds);
+ // 子系统id中文名字典
var subSystemIds = result.List.Select(x => x.SubSystemId).ToHashSet();
- var subSystemDict = (await _vSystemQueries
- .GetListAsync(x => subSystemIds.Contains(x.Id), x => new
- {
- x.Id,
- x.CnName
- })).ToDictionary(x => x.Id, x => x.CnName);
+ var subSystemDict = await _systemCnNameDictCache.SafeGetBatchAsync(subSystemIds);
var map = result.List.Select(x => new ReturnWarningDetailsDto
{
@@ -261,7 +256,7 @@ public class ReturnWarningService : ApplicationService
// 1.查出预警明细
var ids = input.WarningDetailIds.ToHashSet();
- var warningDetails = await _warningDetailsEsRepository.GetReturnWarningDetailsAsync(new GetReturnWarningDetailsVO()
+ var warningDetails = await _warningDetailsEsRepository.GetReturnWarningDetailsAsync(new GetReturnWarningDetailsVO
{
DetailsIds = ids
});
@@ -309,7 +304,6 @@ public class ReturnWarningService : ApplicationService
{
[detail.OrderId] = KeyValuePair.Create(detail.TrackEsId, detail.TrackVersion)
},
- // OrderIds = new[] { order.Id },
TrackCode = detail.TrackCode,
OperationMan = userInfo.Data.UserName,
SystemPushInfo = new SystemPushStruct
diff --git a/src/SJZY.Track.Application/Services/Warning/TransportWarningService.cs b/src/SJZY.Track.Application/Services/Warning/TransportWarningService.cs
index f25b817a..5dd4b4b7 100644
--- a/src/SJZY.Track.Application/Services/Warning/TransportWarningService.cs
+++ b/src/SJZY.Track.Application/Services/Warning/TransportWarningService.cs
@@ -1,4 +1,5 @@
using SJZY.Expand.ABP.Core.PublicMethords;
+using SJZY.Track.Application.Caching;
using SJZY.Track.Application.Contract.Dtos.Warning;
using SJZY.Track.Application.Contract.Dtos.Warning.Transport;
using SJZY.Track.Application.Helpers;
@@ -7,13 +8,11 @@ using SJZY.Track.Application.Services.Warning.Model;
using SJZY.Track.Domain.Aggregates.KPIAreaAggregate;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
-using SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
using SJZY.Track.Domain.Aggregates.WarningAggregate;
using SJZY.Track.Domain.Aggregates.WarningAggregate.Transport;
using SJZY.Track.Domain.Dtos.Warning;
using SJZY.Track.Domain.Enums;
using SJZY.Track.Domain.Extensions;
-using SJZY.Track.Domain.Queries;
namespace SJZY.Track.Application.Services.Warning;
@@ -25,26 +24,36 @@ namespace SJZY.Track.Application.Services.Warning;
public class TransportWarningService : ApplicationService
{
private readonly IOrderRepository _orderRepository;
- private readonly IVExternalSubjectQueries _vExternalSubjectQueries;
- private readonly IVSystemQueries _vSystemQueries;
+ private readonly IKpiAreaRepository _kpiAreaRepository;
private readonly IWarningRuleRepository _warningRuleRepository;
private readonly IWarningDetailsEsRepository _warningDetailsEsRepository;
- private readonly ITransportWarningHandler _transportWarningHandler;
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
- private readonly ITrackStatusRepository _trackStatusRepository;
- private readonly IKpiAreaRepository _kpiAreaRepository;
+ private readonly ITransportWarningHandler _transportWarningHandler;
+ private readonly TrackStatusNameDictCache _trackStatusNameDictCache;
+ private readonly CustomAbbreviationDictCache _customAbbreviationDictCache;
+ private readonly SystemCnNameDictCache _systemCnNameDictCache;
- public TransportWarningService(IWarningRuleRepository warningRuleRepository, IWarningDetailsEsRepository warningDetailsEsRepository, ITransportWarningHandler transportWarningHandler, ITrackDetailsEsRepository trackDetailsEsRepository, ITrackStatusRepository trackStatusRepository, IKpiAreaRepository kpiAreaRepository, IOrderRepository orderRepository, IVExternalSubjectQueries vExternalSubjectQueries, IVSystemQueries vSystemQueries)
+ public TransportWarningService(
+ IOrderRepository orderRepository,
+ IKpiAreaRepository kpiAreaRepository,
+ IWarningRuleRepository warningRuleRepository,
+ IWarningDetailsEsRepository warningDetailsEsRepository,
+ ITrackDetailsEsRepository trackDetailsEsRepository,
+ ITransportWarningHandler transportWarningHandler,
+ TrackStatusNameDictCache trackStatusNameDictCache,
+ CustomAbbreviationDictCache customAbbreviationDictCache,
+ SystemCnNameDictCache systemCnNameDictCache
+ )
{
+ _orderRepository = orderRepository;
+ _kpiAreaRepository = kpiAreaRepository;
_warningRuleRepository = warningRuleRepository;
_warningDetailsEsRepository = warningDetailsEsRepository;
- _transportWarningHandler = transportWarningHandler;
_trackDetailsEsRepository = trackDetailsEsRepository;
- _trackStatusRepository = trackStatusRepository;
- _kpiAreaRepository = kpiAreaRepository;
- _orderRepository = orderRepository;
- _vExternalSubjectQueries = vExternalSubjectQueries;
- _vSystemQueries = vSystemQueries;
+ _transportWarningHandler = transportWarningHandler;
+ _trackStatusNameDictCache = trackStatusNameDictCache;
+ _customAbbreviationDictCache = customAbbreviationDictCache;
+ _systemCnNameDictCache = systemCnNameDictCache;
}
///
@@ -60,11 +69,10 @@ public class TransportWarningService : ApplicationService
var areaIds = entities
.Select(x => x.AreaId)
- .Where(x => x != null)
+ .Where(x => x > 0)
.Select(x => x!.Value)
.ToHashSet();
- // todo:缓存优化
Dictionary? areaNameDict = null;
if (areaIds.Count > 0)
{
@@ -136,17 +144,12 @@ public class TransportWarningService : ApplicationService
{
var entities = await _warningRuleRepository.GetTransportSceneRuleItemsAsync(input.WarningId, input.SceneId);
- // todo:缓存优化
var trackStatusIds = entities.SelectMany(x => new List(2)
{
x.StartTrackStatusId,
x.EndTrackStatusId
}).ToHashSet();
- var trackStatusDict = (await _trackStatusRepository.GetListAsync(x => trackStatusIds.Contains(x.Id), x => new
- {
- x.Id,
- x.Status
- })).ToDictionary(x => x.Id, y => y.Status);
+ var trackStatusDict = await _trackStatusNameDictCache.SafeGetBatchAsync(trackStatusIds);
var map = entities.Select(x => new TransportWarningSceneRuleItemDto
{
@@ -190,25 +193,14 @@ public class TransportWarningService : ApplicationService
// 查轨迹状态最早轨迹
var orderIdTrackStatusEarliestTrackDict = await _trackDetailsEsRepository.GetTrackStatusEarliestDictAsync(orderIds);
- // todo:缓存优化
- // 订单类型
+ // 订单类型名称字典
var orderTypeDict = await _orderRepository.GetTrackOrderTypeDictAsync();
- // 客户简称
+ // 客户id简称字典
var customIds = result.List.Select(x => x.CustomId).ToHashSet();
- var customDict = (await _vExternalSubjectQueries
- .GetListAsync(x => customIds.Contains(x.Id), x => new
- {
- x.Id,
- x.Abbreviation
- })).ToDictionary(x => x.Id, x => x.Abbreviation);
- // 子系统
+ var customDict = await _customAbbreviationDictCache.SafeGetBatchAsync(customIds);
+ // 子系统id中文名字典
var subSystemIds = result.List.Select(x => x.SubSystemId).ToHashSet();
- var subSystemDict = (await _vSystemQueries
- .GetListAsync(x => subSystemIds.Contains(x.Id), x => new
- {
- x.Id,
- x.CnName
- })).ToDictionary(x => x.Id, x => x.CnName);
+ var subSystemDict = await _systemCnNameDictCache.SafeGetBatchAsync(subSystemIds);
var map = result.List.Select(x =>
{
diff --git a/src/SJZY.Track.Application/Services/Warning/WarningService.cs b/src/SJZY.Track.Application/Services/Warning/WarningService.cs
index 695dbc6a..bba24081 100644
--- a/src/SJZY.Track.Application/Services/Warning/WarningService.cs
+++ b/src/SJZY.Track.Application/Services/Warning/WarningService.cs
@@ -1,8 +1,8 @@
+using SJZY.Track.Application.Caching;
using SJZY.Track.Application.Contract.Dtos.Warning;
using SJZY.Track.Application.Services.Warning.Handlers;
using SJZY.Track.Domain.Aggregates.WarningAggregate;
using SJZY.Track.Domain.Enums;
-using SJZY.Track.Domain.Queries;
namespace SJZY.Track.Application.Services.Warning;
@@ -14,20 +14,27 @@ namespace SJZY.Track.Application.Services.Warning;
public class WarningService : ApplicationService
{
private readonly IWarningRuleRepository _warningRuleRepository;
- private readonly IVSystemQueries _vSystemQueries;
- private readonly IVExternalSubjectQueries _vExternalSubjectQueries;
private readonly ICompleteWarningHandler _completeWarningHandler;
private readonly ITransportWarningHandler _transportWarningHandler;
private readonly IReturnWarningHandler _returnWarningHandler;
+ private readonly CustomAbbreviationDictCache _customAbbreviationDictCache;
+ private readonly SystemCnNameDictCache _systemCnNameDictCache;
- public WarningService(IWarningRuleRepository warningRuleRepository, IVSystemQueries vSystemQueries, IVExternalSubjectQueries vExternalSubjectQueries, IReturnWarningHandler returnWarningHandler, ITransportWarningHandler transportWarningHandler, ICompleteWarningHandler completeWarningHandler)
+ public WarningService(
+ IWarningRuleRepository warningRuleRepository,
+ ICompleteWarningHandler completeWarningHandler,
+ ITransportWarningHandler transportWarningHandler,
+ IReturnWarningHandler returnWarningHandler,
+ CustomAbbreviationDictCache customAbbreviationDictCache,
+ SystemCnNameDictCache systemCnNameDictCache
+ )
{
_warningRuleRepository = warningRuleRepository;
- _vSystemQueries = vSystemQueries;
- _vExternalSubjectQueries = vExternalSubjectQueries;
- _returnWarningHandler = returnWarningHandler;
- _transportWarningHandler = transportWarningHandler;
_completeWarningHandler = completeWarningHandler;
+ _transportWarningHandler = transportWarningHandler;
+ _returnWarningHandler = returnWarningHandler;
+ _customAbbreviationDictCache = customAbbreviationDictCache;
+ _systemCnNameDictCache = systemCnNameDictCache;
}
///
@@ -42,22 +49,12 @@ public class WarningService : ApplicationService
if (result.Count == 0)
return new UnifyResultDto>(true, new List());
- // todo:缓存优化
+ // 客户id简称字典
var customIds = result.Select(x => x.CustomId).ToHashSet();
- var customDict = (await _vExternalSubjectQueries
- .GetListAsync(x => customIds.Contains(x.Id), x => new
- {
- x.Id,
- x.Abbreviation
- })).ToDictionary(x => x.Id, x => x.Abbreviation);
-
+ var customDict = await _customAbbreviationDictCache.SafeGetBatchAsync(customIds);
+ // 子系统id中文名字典
var subSystemIds = result.Select(x => x.SubSystemId).ToHashSet();
- var subSystemDict = (await _vSystemQueries
- .GetListAsync(x => subSystemIds.Contains(x.Id), x => new
- {
- x.Id,
- x.CnName
- })).ToDictionary(x => x.Id, x => x.CnName);
+ var subSystemDict = await _systemCnNameDictCache.SafeGetBatchAsync(subSystemIds);
return new UnifyResultDto>(true, result.Select(x => new WarningRuleDto
{
diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs
index 19b642ae..950444cc 100644
--- a/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs
+++ b/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs
@@ -91,4 +91,9 @@ public partial class GlobalConst
/// 轨迹中台hangfire key前缀
///
public const string TrackHangfireKeyPrefix = "TrackHangfire";
+
+ ///
+ /// 轨迹中台数据字典key前缀
+ ///
+ public const string TrackDataDictKeyPrefix = "TrackDataDict";
}