207 lines
8.1 KiB
C#
207 lines
8.1 KiB
C#
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;
|
||
}
|
||
}
|
||
}
|
||
|