using System; using System.Collections.Generic; using System.Linq; using VolPro.Core.Configuration; using VolPro.Core.Const; using VolPro.Core.DBManager; using VolPro.Core.Enums; using VolPro.Core.Extensions; using VolPro.Core.ManageUser; using VolPro.Core.UserManager; namespace VolPro.Core.Extensions { public static class IdentitySqlCode { public static void CreateCode( Dictionary mainData, string tableName, List tableColumns = null, string leftQuote = null, string rightQuote = null) { // 1) 读取编码规则 var query = IdentityCode.CodeRules.Where(x => !string.IsNullOrEmpty(x.TableName) && x.TableName.Equals(tableName, StringComparison.OrdinalIgnoreCase)); if (AppSetting.UseDynamicShareDB) { query = query.Where(x => x.DbServiceId == UserContext.CurrentServiceId); } else { if (AppSetting.TenancyField != null) { query = query.Where(x => x.TenancyId == UserContext.CurrentServiceId.ToString()); } } var rule = query.OrderByDescending(x => x.CreateDate).FirstOrDefault(); if (rule == null) return; RuleIncremental ruleIncremental = RuleIncremental.day; try { ruleIncremental = (RuleIncremental)Enum.Parse(typeof(RuleIncremental), rule.RuleIncremental); } catch { ruleIncremental = RuleIncremental.day; } // 2) 映射单据字段(rule.Field 可能大小写/别名与实际列名不一致) string codeFieldName = rule.Field; if (tableColumns != null && !string.IsNullOrEmpty(codeFieldName)) { var col = tableColumns.FirstOrDefault(c => c.ColumnName.Equals(codeFieldName, StringComparison.OrdinalIgnoreCase)); if (col != null) codeFieldName = col.ColumnName; } if (string.IsNullOrEmpty(codeFieldName)) return; // 3) 找到业务表真实表名与库 var tableInfo = TableColumnContext.TableInfo.FirstOrDefault(x => !string.IsNullOrEmpty(x.TableName) && x.TableName.Equals(tableName, StringComparison.OrdinalIgnoreCase)); if (tableInfo == null) return; string dbTableName = string.IsNullOrEmpty(tableInfo.TableTrueName) ? tableInfo.TableName : tableInfo.TableTrueName; string dbService = tableInfo.DBServer; if (string.IsNullOrEmpty(dbService)) return; // 4) 构造规则前缀与日期起点 string preCode = rule.PrefixCode ?? ""; string concatenationSymbol = rule.ConcatenationSymbol ?? ""; string dateFormat = rule.RuleType; if (dateFormat == RuleIncremental.none.ToString()) { dateFormat = null; } DateTime? dateNow = null; switch (ruleIncremental) { case RuleIncremental.day: dateNow = (DateTime)DateTime.Now.ToString("yyyy-MM-dd").GetDateTime(); break; case RuleIncremental.month: dateNow = (DateTime)DateTime.Now.ToString("yyyy-MM-01").GetDateTime(); break; case RuleIncremental.year: dateNow = (DateTime)DateTime.Now.ToString("yyyy-01-01").GetDateTime(); break; case RuleIncremental.none: default: break; } string dateText = dateNow?.ToString("yyyy-MM-dd") ?? "none"; string dateFieldName = !string.IsNullOrWhiteSpace(rule.OrderFiled) ? rule.OrderFiled : AppSetting.CreateMember.DateField; // 5) 共享缓存key(与 IdentityCode.CreateList 保持同形态,避免并发重复) string serviceId = ""; if (AppSetting.UseDynamicShareDB || !string.IsNullOrEmpty(AppSetting.TenancyField)) { serviceId = $"_{UserContext.CurrentServiceId}"; } string cacheKey = $"{tableName}_{ruleIncremental}_{dateText}{serviceId}"; // 6) 自增流水号:同一 cacheKey 下,保证并发安全 int number = IdentityCode._counters.AddOrUpdate( cacheKey, addValueFactory: (k) => { // 获取库类型决定左右引号(MySql: ``, SqlServer: [ ]) string dbType = DbRelativeCache.GetDbType(dbService) ?? DBType.Name; DbCurrentType dbCurrentType = (DbCurrentType)Enum.Parse(typeof(DbCurrentType), dbType, true); int last = GetLastIncrementBySql( dbService, dbTableName, codeFieldName, preCode, dateFieldName, dateNow, rule.ValueLen, leftQuote, rightQuote); return last + 1; }, updateValueFactory: (k, existingValue) => existingValue + 1); // 7) 生成最终编码字符串 string ruleText = dateFormat == null ? preCode : $"{preCode}{concatenationSymbol}{DateTime.Now.ToString(dateFormat)}"; string code = $"{ruleText}{concatenationSymbol}{(number).ToString("D" + rule.ValueLen)}"; mainData[codeFieldName] = code; } private static int GetLastIncrementBySql( string dbService, string dbTableName, string codeFieldName, string preCode, string dateFieldName, DateTime? dateNow, int len, string leftQuote, string rightQuote) { string table = $"{leftQuote}{dbTableName}{rightQuote}"; string codeField = $"{leftQuote}{codeFieldName}{rightQuote}"; string dateField = string.IsNullOrWhiteSpace(dateFieldName) ? null : $"{leftQuote}{dateFieldName}{rightQuote}"; string sqlWhere = $"{codeField} LIKE @preCodeLike"; if (dateNow != null && !string.IsNullOrEmpty(dateField)) { sqlWhere += $" AND {dateField} >= @dateNow"; } // 取最后一条:按 codeField 倒序取 1 条 // 这里不再通过 leftQuote/rightQuote 推断 DB 类型,所以按 dbService 取一次 DB 类型决定 SQL 语法 string dbType = DbRelativeCache.GetDbType(dbService) ?? DBType.Name; DbCurrentType dbCurrentType = (DbCurrentType)Enum.Parse(typeof(DbCurrentType), dbType, true); string sql; if (dbCurrentType == DbCurrentType.MsSql) { sql = $"SELECT TOP 1 {codeField} FROM {table} WHERE {sqlWhere} ORDER BY {codeField} DESC"; } else if (dbCurrentType == DbCurrentType.Oracle) { sql = $"SELECT {codeField} FROM {table} WHERE {sqlWhere} ORDER BY {codeField} DESC FETCH FIRST 1 ROWS ONLY"; } else { sql = $"SELECT {codeField} FROM {table} WHERE {sqlWhere} ORDER BY {codeField} DESC LIMIT 1"; } var dapper = DbSqlSugar.DbManger.GetConnection(dbService); string lastCode = dapper.Ado.SqlQuery(sql, new { preCodeLike = $"{preCode}%", dateNow }).FirstOrDefault(); if (string.IsNullOrEmpty(lastCode)) return 0; if (lastCode.Length >= len) { return int.TryParse(lastCode.Substring(lastCode.Length - len), out var n) ? n : 0; } return 0; } } }