using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; using SqlSugar; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using WIDESEA_Core.BaseRepository; using WIDESEA_Core.BaseServices; using WIDESEA_Core.Seed; using WIDESEA_IBasicService; using WIDESEA_Model.Models; using WIDESEA_Model.Models.Basic; namespace WIDESEA_BasicService { public class DailySequenceService : ServiceBase>, IDailySequenceService { private readonly ILogger _logger; private readonly IMemoryCache _cache; private readonly SemaphoreSlim _lock = new(1, 1); private readonly IUnitOfWorkManage _unitOfWorkManage; public DailySequenceService(IRepository BaseDal, ILogger logger, IMemoryCache cache, IUnitOfWorkManage unitOfWorkManage) : base(BaseDal) { _logger = logger; _cache = cache; _unitOfWorkManage = unitOfWorkManage; } public IRepository Repository => BaseDal; public async Task GetNextSequenceAsync() { return await GetNextSequenceAsync("MESBarcode"); } public async Task GetNextSequence2Async(string sequenceKey) { var today = DateTime.Today; var cacheKey = $"DailySequence_{sequenceKey}_{today:yyyyMMdd}"; await _lock.WaitAsync(); try { // 先检查缓存 if (_cache.TryGetValue(cacheKey, out int currentValue)) { currentValue++; _cache.Set(cacheKey, currentValue, TimeSpan.FromHours(24)); return currentValue; } // 缓存中没有,从数据库获取或创建 var result= await Repository.Db.Ado.UseTranAsync(async () => { // 清理昨天的记录 var yesterday = today.AddDays(-1); await Repository.Db.Deleteable() .Where(x => x.SequenceDate == yesterday && x.SequenceKey == sequenceKey) .ExecuteCommandAsync(); // 查找或创建今天的记录 var sequence = await Repository.Db.Queryable() .Where(x => x.SequenceDate == today && x.SequenceKey == sequenceKey) .With(SqlWith.UpdLock) .FirstAsync(); int nextValue; if (sequence == null) { sequence = new DT_DailySequence { SequenceDate = today, SequenceKey = sequenceKey, CurrentValue = 1, }; await Repository.Db.Insertable(sequence).ExecuteReturnEntityAsync(); nextValue = 1; } else { nextValue = sequence.CurrentValue + 1; sequence.CurrentValue = nextValue; await Repository.Db.Updateable(sequence).ExecuteCommandAsync(); } // 设置缓存 _cache.Set(cacheKey, nextValue, TimeSpan.FromHours(24)); return nextValue; }); return result.Data; } catch (Exception ex) { _logger.LogError(ex, "获取序列号失败,SequenceKey: {SequenceKey}", sequenceKey); throw; } finally { _lock.Release(); } } public async Task GetNextSequenceAsync(string sequenceKey) { var today = DateTime.Today; var cacheKey = $"DailySequence_{sequenceKey}_{today:yyyyMMdd}"; await _lock.WaitAsync(); try { // 检查缓存中是否有今天的序列值 if (!_cache.TryGetValue(cacheKey, out int currentValue)) { // 缓存中没有,从数据库获取或创建 currentValue = await GetOrCreateSequenceFromDatabase(today, sequenceKey); // 设置缓存,过期时间为今天结束 var _cacheOptions = new MemoryCacheEntryOptions { AbsoluteExpiration = today.AddDays(1) }; _cache.Set(cacheKey, currentValue, _cacheOptions); return currentValue; } // 缓存中存在,递增并更新缓存 currentValue++; var cacheOptions = new MemoryCacheEntryOptions { AbsoluteExpiration = today.AddDays(1) }; _cache.Set(cacheKey, currentValue, cacheOptions); // 异步更新到数据库 _ = Task.Run(async () => { try { await UpdateSequenceInDatabase(today, sequenceKey, currentValue); } catch (Exception ex) { _logger.LogWarning(ex, "异步更新序列到数据库失败,SequenceKey: {SequenceKey}", sequenceKey); } }); return currentValue; } finally { _lock.Release(); } } private async Task GetOrCreateSequenceFromDatabase(DateTime date, string sequenceKey) { var result= await Repository.Db.Ado.UseTranAsync(async () => { var sequence = await Repository.Db.Queryable() .Where(x => x.SequenceDate == date && x.SequenceKey == sequenceKey) .With(SqlWith.UpdLock) .FirstAsync(); if (sequence == null) { sequence = new DT_DailySequence { SequenceDate = date, SequenceKey = sequenceKey, CurrentValue = 1, }; await Repository.Db.Insertable(sequence).ExecuteReturnEntityAsync(); return 1; } else { var nextValue = sequence.CurrentValue + 1; sequence.CurrentValue = nextValue; await Repository.Db.Updateable(sequence).ExecuteCommandAsync(); return nextValue; } }) ; return result.Data; } private async Task UpdateSequenceInDatabase(DateTime date, string sequenceKey, int value) { try { using SqlSugarClient sugarClient = new SqlSugarClient(new ConnectionConfig { IsAutoCloseConnection = true, DbType = DbType.SqlServer, ConnectionString = DBContext.ConnectionString }); var result = await sugarClient.Updateable() .SetColumns(it => new DT_DailySequence() { CurrentValue = value, }) .Where(it => it.SequenceDate == date && it.SequenceKey == sequenceKey) .ExecuteCommandAsync(); if (result == 0) { // 如果没有更新到记录,可能是首次使用,插入新记录 var newSequence = new DT_DailySequence { SequenceKey = sequenceKey, SequenceDate = date, CurrentValue = value, Creater="admin", CreateDate=DateTime.Now, }; await sugarClient.Insertable(newSequence).ExecuteCommandAsync(); } } catch (Exception ex) { // 记录日志并重新抛出异常 Console.WriteLine($"更新序列失败: {ex.Message}"); throw; } } public async Task CleanOldSequencesAsync(int keepDays = 30) { try { var deleteBefore = DateTime.Today.AddDays(-keepDays); var deletedCount = await Repository.Db.Deleteable() .Where(x => x.SequenceDate < deleteBefore) .ExecuteCommandAsync(); for (int i = 1; i < keepDays; i++) { var cacheKey = $"DailySequence_MESBarcode_{DateTime.Now.AddDays(-i):yyyyMMdd}"; _cache.Remove(cacheKey); } _logger.LogInformation("清理了 {Count} 条 {Days} 天前的序列记录", deletedCount, keepDays); } catch (Exception ex) { _logger.LogError(ex, "清理旧序列记录失败"); throw; } } } }