From 4835af760b2ea1e3ba161b859770251e47e36536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E4=BD=A0=E4=B8=AA=E6=97=BA=E5=91=80?= Date: Wed, 14 May 2025 21:49:59 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=92=A1refactor(=E8=A1=A8=E5=AE=9E?= =?UTF-8?q?=E4=BD=93=E5=88=9D=E5=A7=8B=E5=8C=96):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E8=A1=A8=E7=BB=93=E6=9E=84=E5=88=9D=E5=A7=8B=E5=8C=96=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Extension/RepositoryExtension.cs | 35 +++++++++++++++++++ .../Admin.NET.Core/SqlSugar/SqlSugarSetup.cs | 30 ++++++++-------- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/Admin.NET/Admin.NET.Core/Extension/RepositoryExtension.cs b/Admin.NET/Admin.NET.Core/Extension/RepositoryExtension.cs index 3937de05..83894b4c 100644 --- a/Admin.NET/Admin.NET.Core/Extension/RepositoryExtension.cs +++ b/Admin.NET/Admin.NET.Core/Extension/RepositoryExtension.cs @@ -444,4 +444,39 @@ public static class RepositoryExtension throw Oops.Oh(error); } } + + /// + /// 初始化表实体 + /// + /// + /// + /// + public static void InitTable(this SqlSugarScopeProvider dbProvider) where T : class, new() + { + InitTable(dbProvider, typeof(T)); + } + + /// + /// 初始化表实体 + /// + /// + /// + /// + public static void InitTable(this SqlSugarScopeProvider dbProvider, Type entityType) + { + // 初始化表实体,如果存在分表特性,需要额外处理 + if (entityType.GetCustomAttribute() == null) + dbProvider.CodeFirst.InitTables(entityType); + else + dbProvider.CodeFirst.SplitTables().InitTables(entityType); + + // 将不存在实体中的字段改为可空 + var entityInfo = dbProvider.EntityMaintenance.GetEntityInfo(entityType); + var dbColumnInfos = dbProvider.DbMaintenance.GetColumnInfosByTableName(entityInfo.DbTableName) ?? []; + foreach (var dbColumnInfo in dbColumnInfos.Where(dbColumnInfo => !dbColumnInfo.IsPrimarykey && entityInfo.Columns.All(u => u.DbColumnName != dbColumnInfo.DbColumnName))) + { + dbColumnInfo.IsNullable = true; + dbProvider.DbMaintenance.UpdateColumn(entityInfo.DbTableName, dbColumnInfo); + } + } } \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs b/Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs index fa5bd928..27332b04 100644 --- a/Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs +++ b/Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs @@ -391,26 +391,26 @@ public static class SqlSugarSetup else entityTypes = entityTypes.Where(u => u.GetCustomAttribute()?.configId.ToString() == config.ConfigId.ToString()).ToList(); // 自定义的库 + var semaphore = new SemaphoreSlim(8); // 并发限制数量 int taskIndex = 0, entityTypeCount = entityTypes.Count; var taskList = entityTypes.Select(entityType => Task.Run(() => { - DateTime st = DateTime.Now; - if (entityType.GetCustomAttribute() == null) - dbProvider.CodeFirst.InitTables(entityType); - else - dbProvider.CodeFirst.SplitTables().InitTables(entityType); - // 将不存在实体中的字段改为可空 - var entityInfo = dbProvider.EntityMaintenance.GetEntityInfo(entityType); - var dbColumnInfos = dbProvider.DbMaintenance.GetColumnInfosByTableName(entityInfo.DbTableName) ?? []; - var tempDbColumnInfo = dbColumnInfos.Where(dbColumnInfo => !dbColumnInfo.IsPrimarykey && entityInfo.Columns.All(u => u.DbColumnName != null && u.DbColumnName?.ToLower() != dbColumnInfo.DbColumnName?.ToLower())); - foreach (var dbColumnInfo in tempDbColumnInfo) + semaphore.Wait(); // 获取信号量许可 + try { - dbColumnInfo.IsNullable = true; - dbProvider.DbMaintenance.UpdateColumn(entityInfo.DbTableName, dbColumnInfo); + var stopWatch = Stopwatch.StartNew(); // 开始计时 + + dbProvider.InitTable(entityType); // 同步表结构 + + stopWatch.Stop(); // 停止计时 + + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine($"初始化表 {entityType,-64} ({config.ConfigId} - {Interlocked.Increment(ref taskIndex):D003}/{entityTypeCount:D003}) 用时:{stopWatch.ElapsedMilliseconds}ms"); + } + finally + { + semaphore.Release(); // 释放信号量许可 } - DateTime et = DateTime.Now; - Console.ForegroundColor = ConsoleColor.Green; - Console.WriteLine($"初始化表 {entityType,-64} ({config.ConfigId} - {Interlocked.Increment(ref taskIndex):D003}/{entityTypeCount:D003}) 用时:{et.Subtract(st).TotalMilliseconds}ms"); })); Task.WaitAll(taskList.ToArray()); } From 3a39a1da9b798cec428fb00123aa162fafa3af75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E4=BD=A0=E4=B8=AA=E6=97=BA=E5=91=80?= Date: Wed, 14 May 2025 23:04:49 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=A7=A8refactor(=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=E7=A7=8D=E5=AD=90=E6=95=B0=E6=8D=AE):=20=E7=A7=8D?= =?UTF-8?q?=E5=AD=90=E6=95=B0=E6=8D=AE=E5=88=9D=E5=A7=8B=E5=8C=96=E9=87=8D?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Extension/RepositoryExtension.cs | 107 ++++++++++++++++++ .../Admin.NET.Core/SqlSugar/SqlSugarSetup.cs | 93 ++++----------- 2 files changed, 127 insertions(+), 73 deletions(-) diff --git a/Admin.NET/Admin.NET.Core/Extension/RepositoryExtension.cs b/Admin.NET/Admin.NET.Core/Extension/RepositoryExtension.cs index 83894b4c..c1b6fd49 100644 --- a/Admin.NET/Admin.NET.Core/Extension/RepositoryExtension.cs +++ b/Admin.NET/Admin.NET.Core/Extension/RepositoryExtension.cs @@ -479,4 +479,111 @@ public static class RepositoryExtension dbProvider.DbMaintenance.UpdateColumn(entityInfo.DbTableName, dbColumnInfo); } } + + /// + /// 初始化表种子数据 + /// + /// + /// + /// + public static (int, int, int)? InitTableSeedData(this SqlSugarScope db, Action handleBefore = null) + { + return InitTableSeedData(db, typeof(T), handleBefore); + } + + /// + /// 初始化表种子数据 + /// + /// + /// + /// + /// + public static (int, int, int)? InitTableSeedData(this SqlSugarScope db, Type seedType, Action handleBefore = null) + { + var config = db.CurrentConnectionConfig; + var dbProvider = db.GetConnectionScope(config.ConfigId); + + // 获取表实体类型 + var entityType = seedType.GetInterfaces().First().GetGenericArguments().First(); + + if (config.ConfigId.ToString() == SqlSugarConst.MainConfigId) // 默认库(有系统表特性、没有日志表和租户表特性) + { + if (entityType.GetCustomAttribute() == null && + (entityType.GetCustomAttribute() != null || + entityType.GetCustomAttribute() != null)) + return default; + } + else if (config.ConfigId.ToString() == SqlSugarConst.LogConfigId) // 日志库 + { + if (entityType.GetCustomAttribute() == null) return default; + } + else + { + var att = entityType.GetCustomAttribute(); // 自定义的库 + if (att == null || att.configId.ToString() != config.ConfigId.ToString()) return default; + } + + var instance = Activator.CreateInstance(seedType); + var hasDataMethod = seedType.GetMethod("HasData"); + var seedData = ((IEnumerable)hasDataMethod?.Invoke(instance, null))?.Cast().ToArray() ?? []; + if (!seedData.Any()) return default; + + // 若实体包含Id字段,则设置为当前租户Id递增1 + var idProp = entityType.GetProperty(nameof(EntityBaseId.Id)); + var entityInfo = dbProvider.EntityMaintenance.GetEntityInfo(entityType); + if (idProp != null && entityInfo.Columns.Any(u => u.PropertyName == nameof(EntityBaseId.Id))) + { + var seedId = config.ConfigId.ToLong(); + foreach (var sd in seedData) + { + var id = idProp!.GetValue(sd, null); + if (id == null || id.ToString() == "0" || string.IsNullOrWhiteSpace(id.ToString())) + idProp.SetValue(sd, ++seedId); + } + } + + // 执行前处理种子数据 + if (handleBefore != null) foreach (var sd in seedData) handleBefore(sd); + + int total, insertCount = 0, updateCount = 0; + if (entityType.GetCustomAttribute(true) != null) + { + // 拆分表的操作需要实体类型,而通过反射很难实现 + // 所以,这里将Init方法写在“种子数据类”内部,再传入 db 反射调用 + var hasInitMethod = seedType.GetMethod("Init"); + var parameters = new object[] { db }; + var result = hasInitMethod?.Invoke(instance, parameters) as (int, int, int)?; + total = result?.Item1 ?? 0; + insertCount = result?.Item2 ?? 0; + updateCount = result?.Item3 ?? 0; + } + else + { + var seedDataList = seedData.ToList(); + total = seedDataList.Count; + + // 按主键进行批量增加和更新 + if (entityInfo.Columns.Any(u => u.IsPrimarykey)) + { + // 先修改再插入,否则会更新修改时间字段 + var storage = dbProvider.StorageableByObject(seedDataList).ToStorage(); + if (seedType.GetCustomAttribute() == null) // 有忽略更新种子特性时则不更新 + { + updateCount = storage.AsUpdateable.IgnoreColumns(entityInfo.Columns.Where(u => u.PropertyInfo.GetCustomAttribute() != null) + .Select(u => u.PropertyName).ToArray()).ExecuteCommand(); + } + insertCount = storage.AsInsertable.ExecuteCommand(); + } + // 无主键则只进行插入 + else + { + if (!dbProvider.Queryable(entityInfo.DbTableName, entityInfo.DbTableName).Any()) + { + insertCount = seedDataList.Count; + dbProvider.InsertableByObject(seedDataList).ExecuteCommand(); + } + } + } + return (total, insertCount, updateCount); + } } \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs b/Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs index 27332b04..38ad930f 100644 --- a/Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs +++ b/Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs @@ -392,7 +392,7 @@ public static class SqlSugarSetup entityTypes = entityTypes.Where(u => u.GetCustomAttribute()?.configId.ToString() == config.ConfigId.ToString()).ToList(); // 自定义的库 var semaphore = new SemaphoreSlim(8); // 并发限制数量 - int taskIndex = 0, entityTypeCount = entityTypes.Count; + int taskIndex = 0, size = entityTypes.Count; var taskList = entityTypes.Select(entityType => Task.Run(() => { semaphore.Wait(); // 获取信号量许可 @@ -405,7 +405,7 @@ public static class SqlSugarSetup stopWatch.Stop(); // 停止计时 Console.ForegroundColor = ConsoleColor.Green; - Console.WriteLine($"初始化表 {entityType,-64} ({config.ConfigId} - {Interlocked.Increment(ref taskIndex):D003}/{entityTypeCount:D003}) 用时:{stopWatch.ElapsedMilliseconds}ms"); + Console.WriteLine($"初始化表 {entityType,-64} ({config.ConfigId} - {Interlocked.Increment(ref taskIndex):D003}/{size:D003}) 耗时:{stopWatch.ElapsedMilliseconds} ms"); } finally { @@ -519,89 +519,36 @@ public static class SqlSugarSetup /// private static void InitSeedData(SqlSugarScope db, DbConnectionConfig config) { - SqlSugarScopeProvider dbProvider = db.GetConnectionScope(config.ConfigId); - Log.Information($"初始化种子数据 {config.DbType} - {config.ConfigId}"); var seedDataTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.GetInterfaces().Any(i => i.HasImplementedRawGeneric(typeof(ISqlSugarEntitySeedData<>)))) .Where(u => !u.IsDefined(typeof(TenantSeedAttribute), false)) .WhereIF(config.SeedSettings.EnableIncreSeed, u => u.IsDefined(typeof(IncreSeedAttribute), false)) .OrderBy(u => u.GetCustomAttributes(typeof(SeedDataAttribute), false).Length > 0 ? ((SeedDataAttribute)u.GetCustomAttributes(typeof(SeedDataAttribute), false)[0]).Order : 0).ToList(); - int taskIndex = 0, seedDataTypeCount = seedDataTypes.Count; - foreach (var seedType in seedDataTypes) + var semaphore = new SemaphoreSlim(8); // 并发限制数量 + int taskIndex = 0, size = seedDataTypes.Count; + var taskList = seedDataTypes.Select(seedType => Task.Run(() => { - var entityType = seedType.GetInterfaces().First().GetGenericArguments().First(); - if (config.ConfigId.ToString() == SqlSugarConst.MainConfigId) // 默认库(有系统表特性、没有日志表和租户表特性) + semaphore.Wait(); // 获取信号量许可 + try { - if (entityType.GetCustomAttribute() == null && (entityType.GetCustomAttribute() != null || entityType.GetCustomAttribute() != null)) - return; - } - else if (config.ConfigId.ToString() == SqlSugarConst.LogConfigId) // 日志库 - { - if (entityType.GetCustomAttribute() == null) - return; - } - else - { - var att = entityType.GetCustomAttribute(); // 自定义的库 - if (att == null || att.configId.ToString() != config.ConfigId.ToString()) return; - } + var stopWatch = Stopwatch.StartNew(); // 开始计时 - var instance = Activator.CreateInstance(seedType); - var hasDataMethod = seedType.GetMethod("HasData"); - var seedData = ((IEnumerable)hasDataMethod?.Invoke(instance, null))?.Cast(); - if (seedData == null) return; + // 种子数据初始化 + var tuple = db.InitTableSeedData(seedType); + if (tuple == null) return; - // 若实体包含Id字段,则设置为当前租户Id递增1 - var entityInfo = dbProvider.EntityMaintenance.GetEntityInfo(entityType); - if (entityInfo.Columns.Any(u => u.PropertyName == nameof(EntityBaseId.Id))) - { - var seedId = config.ConfigId.ToLong(); - foreach (var sd in seedData) - { - var id = sd.GetType().GetProperty(nameof(EntityBaseId.Id))!.GetValue(sd, null); - if (id != null && (id.ToString() == "0" || string.IsNullOrWhiteSpace(id.ToString()))) - sd.GetType().GetProperty(nameof(EntityBaseId.Id))!.SetValue(sd, ++seedId); - } - } + stopWatch.Stop(); // 停止计时 - if (entityType.GetCustomAttribute(true) != null) - { - // 拆分表的操作需要实体类型,而通过反射很难实现 - // 所以,这里将Init方法写在“种子数据类”内部,再传入 db 反射调用 - var hasInitMethod = seedType.GetMethod("Init"); - var parameters = new object[] { db }; - hasInitMethod?.Invoke(instance, parameters); - } - else - { - var seedDataList = seedData.ToList(); - int updateCount = 0, insertCount = 0; - // 按主键进行批量增加和更新 - if (entityInfo.Columns.Any(u => u.IsPrimarykey)) - { - // 先修改再插入,否则会更新修改时间字段 - var storage = dbProvider.StorageableByObject(seedDataList).ToStorage(); - if (seedType.GetCustomAttribute() == null) // 有忽略更新种子特性时则不更新 - { - updateCount = storage.AsUpdateable.IgnoreColumns(entityInfo.Columns.Where(u => u.PropertyInfo.GetCustomAttribute() != null) - .Select(u => u.PropertyName).ToArray()).ExecuteCommand(); - } - insertCount = storage.AsInsertable.ExecuteCommand(); - } - // 无主键则只进行插入 - else - { - if (!dbProvider.Queryable(entityInfo.DbTableName, entityInfo.DbTableName).Any()) - { - insertCount = seedDataList.Count; - dbProvider.InsertableByObject(seedDataList).ExecuteCommand(); - } - } Console.ForegroundColor = ConsoleColor.Green; - Console.WriteLine($"初始化种子数据 {seedType.FullName,-58} ({config.ConfigId} - {Interlocked.Increment(ref taskIndex):D003}/{seedDataTypeCount:D003},数据量:{seedDataList.Count:D003},新增 {insertCount:D003} 条记录,更新 {updateCount:D003} 条记录)"); + Console.WriteLine($"初始化种子数据 {seedType.FullName,-58} ({config.ConfigId} - {Interlocked.Increment(ref taskIndex):D003}/{size:D003},数据量:{tuple.Value.Item1:D003},新增 {tuple.Value.Item2:D003} 条记录,更新 {tuple.Value.Item3:D003} 条记录,耗时:{stopWatch.ElapsedMilliseconds:N0} ms)"); } - } + finally + { + semaphore.Release(); // 释放信号量许可 + } + })); + Task.WaitAll(taskList.ToArray()); } /// @@ -649,7 +596,7 @@ public static class SqlSugarSetup var seedDataTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.GetInterfaces().Any(i => i.HasImplementedRawGeneric(typeof(ISqlSugarEntitySeedData<>)))) .Where(u => u.IsDefined(typeof(TenantSeedAttribute), false)) .OrderBy(u => u.GetCustomAttributes(typeof(SeedDataAttribute), false).Length > 0 ? ((SeedDataAttribute)u.GetCustomAttributes(typeof(SeedDataAttribute), false)[0]).Order : 0).ToList(); - if (seedDataTypes == null || seedDataTypes.Count < 1) return; + if (seedDataTypes.Count < 1) return; var db = iTenant.GetConnectionScope(dbConfigId); foreach (var seedType in seedDataTypes) From 0d5bb9f82caa4c34cbc142cb99a639435ead9148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E4=BD=A0=E4=B8=AA=E6=97=BA=E5=91=80?= Date: Wed, 14 May 2025 23:18:48 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=A6=ADfeat:=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=9C=80=E5=A4=A7=E5=B9=B6=E5=8F=91=E6=95=B0=E5=B8=B8=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Admin.NET/Admin.NET.Core/Const/CommonConst.cs | 5 +++++ Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Admin.NET/Admin.NET.Core/Const/CommonConst.cs b/Admin.NET/Admin.NET.Core/Const/CommonConst.cs index ef4638e9..671016d9 100644 --- a/Admin.NET/Admin.NET.Core/Const/CommonConst.cs +++ b/Admin.NET/Admin.NET.Core/Const/CommonConst.cs @@ -21,6 +21,11 @@ public class CommonConst /// 日志分组名称 /// public const string SysLogCategoryName = "System.Logging.LoggingMonitor"; + + /// + /// 最大并发数 + /// + public const int MaxConcurrent = 8; /// /// 事件-增加异常日志 diff --git a/Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs b/Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs index 38ad930f..1cd710ce 100644 --- a/Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs +++ b/Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs @@ -391,7 +391,7 @@ public static class SqlSugarSetup else entityTypes = entityTypes.Where(u => u.GetCustomAttribute()?.configId.ToString() == config.ConfigId.ToString()).ToList(); // 自定义的库 - var semaphore = new SemaphoreSlim(8); // 并发限制数量 + var semaphore = new SemaphoreSlim(CommonConst.MaxConcurrent); // 并发限制数量 int taskIndex = 0, size = entityTypes.Count; var taskList = entityTypes.Select(entityType => Task.Run(() => { @@ -525,7 +525,8 @@ public static class SqlSugarSetup .WhereIF(config.SeedSettings.EnableIncreSeed, u => u.IsDefined(typeof(IncreSeedAttribute), false)) .OrderBy(u => u.GetCustomAttributes(typeof(SeedDataAttribute), false).Length > 0 ? ((SeedDataAttribute)u.GetCustomAttributes(typeof(SeedDataAttribute), false)[0]).Order : 0).ToList(); - var semaphore = new SemaphoreSlim(8); // 并发限制数量 + + var semaphore = new SemaphoreSlim(CommonConst.MaxConcurrent); // 并发限制数量 int taskIndex = 0, size = seedDataTypes.Count; var taskList = seedDataTypes.Select(seedType => Task.Run(() => {