Files
SecMPS/api_sqlsugar/VolPro.Core/Extensions/IdentitySqlCode.cs
2026-05-15 23:22:48 +08:00

207 lines
8.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<string, object> mainData,
string tableName,
List<TableColumnField> 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<string>(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;
}
}
}