在初始化表结构之前和初始化种子数据之后的反射回调,通过系统版本比较,方便系统内部的表结构、种子数据的平滑升级。

This commit is contained in:
FunCoder 2025-04-10 09:04:54 +08:00
parent 7d9c9e3c7e
commit 2032b8d3d5
5 changed files with 181 additions and 0 deletions

View File

@ -19,4 +19,52 @@ public class Startup : AppStartup
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
}
/// <summary>
/// 初始化与升级数据,在初始化表结构之前调用
/// </summary>
/// <param name="dbProvider"></param>
/// <param name="oldVerion">旧版本0表示从来没有设置过-1表示当前连接不是主数据库从SysConfig表获取的</param>
/// <param name="currentVersion">当前版本由ConfigConst.SysCurrentVersion转换的整数版本</param>
public void BeforeInitTable(SqlSugarScopeProvider dbProvider, long oldVerion, long currentVersion)
{
//比较版本号对数据库进行升级结构、种子数据等
}
/// <summary>
/// 初始化与升级数据,在初始化种子数据之后调用
/// </summary>
/// <param name="dbProvider"></param>
/// <param name="oldVerion">旧版本0表示从来没有设置过-1表示当前连接不是主数据库从SysConfig表获取的</param>
/// <param name="currentVersion">当前版本由ConfigConst.SysCurrentVersion转换的整数版本</param>
public void AfterInitSeed(SqlSugarScopeProvider dbProvider, long oldVerion, long currentVersion)
{
//比较版本号对数据库进行升级结构、种子数据等
}
}
/// <summary>
/// 测试InitDatasOrder越大InitDatas执行越靠前
/// </summary>
[AppStartup(1000)]
public class TestStartup : AppStartup
{
/// <summary>
/// 初始化与升级数据,在初始化表结构之前调用
/// </summary>
/// <param name="dbProvider"></param>
/// <param name="oldVerion">旧版本0表示从来没有设置过-1表示当前连接不是主数据库从SysConfig表获取的</param>
/// <param name="currentVersion">当前版本由ConfigConst.SysCurrentVersion转换的整数版本</param>
public void BeforeInitTable(SqlSugarScopeProvider dbProvider, long oldVerion, long currentVersion)
{
//比较版本号对数据库进行升级结构、种子数据等
}
/// <summary>
/// 初始化与升级数据,在初始化种子数据之后调用
/// </summary>
/// <param name="dbProvider"></param>
/// <param name="oldVerion">旧版本0表示从来没有设置过-1表示当前连接不是主数据库从SysConfig表获取的</param>
/// <param name="currentVersion">当前版本由ConfigConst.SysCurrentVersion转换的整数版本</param>
public void AfterInitSeed(SqlSugarScopeProvider dbProvider, long oldVerion, long currentVersion)
{
//比较版本号对数据库进行升级结构、种子数据等
}
}

View File

@ -11,6 +11,15 @@ namespace Admin.NET.Core;
/// </summary>
public class ConfigConst
{
/// <summary>
/// 系统版本code
/// </summary>
public const string SysVersion = "sys_version";
/// <summary>
/// 当前系统版本值,标准版本号为 x.xx.xxxxxx。比如 1.01.250409,也可以是变体,比如 1.2.5 v1.2.5
/// </summary>
public const string SysCurrentVersion = "1.01.000001";
/// <summary>
/// 演示环境
/// </summary>

View File

@ -39,6 +39,8 @@ public class SysConfigSeedData : ISqlSugarEntitySeedData<SysConfig>
new SysConfig{ Id=1300000000261, Name="密码历史记录验证", Code=ConfigConst.SysPasswordRecord, Value="False", SysFlag=YesNoEnum.Y, Remark="是否验证历史密码禁止再次使用", OrderNo=210, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2024-12-17 00:00:00") },
new SysConfig{ Id=1300000000271, Name="显示系统更新日志", Code=ConfigConst.SysUpgrade, Value="True", SysFlag=YesNoEnum.Y, Remark="是否显示系统更新日志", OrderNo=220, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2024-12-20 00:00:00") },
new SysConfig{ Id=1300000000281, Name="开启多语言切换", Code=ConfigConst.SysI18NSwitch, Value="True", SysFlag=YesNoEnum.Y, Remark="是否显示多语言切换按钮", OrderNo=230, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2024-12-20 00:00:00") },
new SysConfig{ Id=1300000000999, Name="系统版本", Code=ConfigConst.SysVersion, Value="0", SysFlag=YesNoEnum.Y, Remark= "系统版本,用于自动升级,请勿手动填写", OrderNo=1000, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
];
}
}

View File

@ -352,6 +352,11 @@ public static class SqlSugarSetup
};
}
private static int GetStartupOrder(Type type)
{
return !type.IsDefined(typeof(AppStartupAttribute), true) ? 0 : type.GetCustomAttribute<AppStartupAttribute>(true).Order;
}
/// <summary>
/// 初始化数据库
/// </summary>
@ -368,6 +373,46 @@ public static class SqlSugarSetup
if (config.DbType != SqlSugar.DbType.Oracle) dbProvider.DbMaintenance.CreateDatabase();
}
// 扫描所有继承 AppStartup 的类
var startups = App.EffectiveTypes
.Where(u => typeof(AppStartup).IsAssignableFrom(u) && u.IsClass && !u.IsAbstract && !u.IsGenericType)
.OrderByDescending(u => GetStartupOrder(u));
//数据库前处理
long oldVerion = 0, currentVersion = 0;
SysConfig versionCfg = null;
try
{
//获取旧版本号
try
{
if (dbProvider.CurrentConnectionConfig.ConfigId.ToString() == SqlSugarConst.MainConfigId)
{
versionCfg = dbProvider.Queryable<SysConfig>().Where(n => n.Code == ConfigConst.SysVersion).First();
oldVerion = versionCfg != null ? CommonUtil.ConvertVersionToLong(versionCfg.Value) : 0;
}
else
{
oldVerion = -1;
}
}
catch (Exception ex) { }
finally
{
currentVersion = CommonUtil.ConvertVersionToLong(ConfigConst.SysCurrentVersion);
}
//执行
foreach (var type in startups)
{
var startup = Activator.CreateInstance(type) as AppStartup;
var initDataMethod = type.GetMethod("BeforeInitTable");
initDataMethod?.Invoke(startup, new[] { (object)dbProvider, oldVerion, currentVersion });
}
}
catch (Exception ex)
{
Log.Information($"数据库前处理有错 {config.DbType} - {config.ConfigId} : {ex.Message}");
}
// 初始化表结构
if (config.TableSettings.EnableInitTable)
{
@ -408,6 +453,41 @@ public static class SqlSugarSetup
// 初始化种子数据
if (config.SeedSettings.EnableInitSeed) InitSeedData(db, config);
//数据后处理
try
{
//执行后处理
foreach (var type in startups)
{
var startup = Activator.CreateInstance(type) as AppStartup;
if (startup == null) continue;
var initDataMethod = type.GetMethod("AfterInitSeed");
if (initDataMethod == null) continue;
initDataMethod?.Invoke(startup, new[] { (object)dbProvider, oldVerion, currentVersion });
}
}
catch (Exception ex)
{
string errr = $"数据库后处理有错 {config.DbType} - {config.ConfigId} : {ex.Message}";
Log.Information(errr);
Console.WriteLine(errr);
Console.WriteLine(ex.StackTrace);
}
finally
{
//最后更新版本
if (dbProvider.CurrentConnectionConfig.ConfigId.ToString() == SqlSugarConst.MainConfigId)
{
IEnumerable<SysConfig> cfgs =
[
new SysConfig{ Id=1300000000999, Name="系统版本", Code=ConfigConst.SysVersion, Value=ConfigConst.SysCurrentVersion, SysFlag=YesNoEnum.Y, Remark= "系统版本,用于自动升级,请勿手动填写", OrderNo=1000, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2022-02-10 00:00:00") }
];
var storage = dbProvider.StorageableByObject(cfgs.ToList()).ToStorage();
storage.AsInsertable.ExecuteCommand();
storage.AsUpdateable.ExecuteCommand();
}
}
}
/// <summary>

View File

@ -39,7 +39,49 @@ public static class CommonUtil
return Math.Abs(hash1 + (hash2 * 1566083941));
}
}
/// <summary>
/// 将版本号转换为长整型,版本格式要求 x.xx.xxxxxx比如 v1.2.5=>102000005 V3.10.42=>310000042
/// </summary>
/// <param name="version">x.xx.xxxxxx</param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public static long ConvertVersionToLong(string version)
{
// 1. 移除所有字母(不区分大小写)
string noLetters = Regex.Replace(version, "[a-zA-Z]", "");
// 2. 按 '.' 分割版本号
string[] parts = noLetters.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
// 3. 确保至少有3部分不足则补 "0"
if (parts.Length < 3)
{
Array.Resize(ref parts, 3);
for (int i = 0; i < parts.Length; i++)
{
parts[i] = string.IsNullOrEmpty(parts[i]) ? "0" : parts[i];
}
}
// 4. 格式化各部分:
// - part1: 至少1位直接取
// - part2: 补齐到2位如 "2" → "02"
// - part3: 补齐到6位如 "5" → "000005"
string part1 = parts[0];
string part2 = parts[1].PadLeft(2, '0');
string part3 = parts[2].PadLeft(6, '0');
// 5. 拼接所有部分并转换为 long
string combined = $"{part1}{part2}{part3}";
if (long.TryParse(combined, out long result))
{
return result;
}
else
{
throw new ArgumentException("版本号转换失败,结果超出 long 范围。");
}
}
/// <summary>
/// 生成百分数
/// </summary>