Ver código fonte

调整多库模式:可以分别控制是否更新库表和种子数据等

zuohuaijun 4 anos atrás
pai
commit
b1307db8c9

+ 9 - 5
Admin.NET/Admin.NET.Application/AppConfig.json

@@ -2,18 +2,22 @@
     "$schema": "https://gitee.com/dotnetchina/Furion/raw/net6/schemas/v3/furion-schema.json",
 
     "DbConnection": {
-        "EnableInitTable": true, // 启用初始化库表
-        "EnableDiffLog": false, // 启用库表差异日志
-        "ConnectionConfigs": [ // 默认第一个为主库
+        "ConnectionConfigs": [
+            // 默认第一个为主库
             {
                 "ConfigId": "Dilon",
                 "DbType": "Sqlite", // MySql、SqlServer、Sqlite、Oracle、PostgreSQL、Dm、Kdbndp、Oscar、MySqlConnector、Access
-                "ConnectionString": "DataSource=./Admin.NET.db"
+                "ConnectionString": "DataSource=./Admin.NET.db",
+                "EnableInitDb": true, // 启用库表初始化
+                "EnableDiffLog": false // 启用库表差异日志
             },
+            // 其他业务库
             {
                 "ConfigId": "Test",
                 "DbType": "Sqlite",
-                "ConnectionString": "DataSource=./Test.db"
+                "ConnectionString": "DataSource=./Test.db",
+                "EnableInitDb": true, // 启用库表初始化
+                "EnableDiffLog": false // 启用库表差异日志
             }
         ]
     },

+ 3 - 3
Admin.NET/Admin.NET.Core/Admin.NET.Core.csproj

@@ -25,9 +25,9 @@
   <ItemGroup>
     <PackageReference Include="AspNetCoreRateLimit" Version="4.0.2" />
     <PackageReference Include="Caching.CSRedis" Version="3.8.669" />
-    <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.4.3" />
-    <PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.4.3" />
-    <PackageReference Include="Furion.Pure" Version="4.4.3" />
+    <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.4.4" />
+    <PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.4.4" />
+    <PackageReference Include="Furion.Pure" Version="4.4.4" />
     <PackageReference Include="Magicodes.IE.Excel" Version="2.6.4" />
     <PackageReference Include="Magicodes.IE.Pdf" Version="2.6.4" />
     <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.9" />

+ 13 - 9
Admin.NET/Admin.NET.Core/Admin.NET.Core.xml

@@ -3190,22 +3190,22 @@
         </member>
         <member name="T:Admin.NET.Core.DbConnectionOptions">
             <summary>
-            数据库链接配置
+            数据库配置选项
             </summary>
         </member>
-        <member name="P:Admin.NET.Core.DbConnectionOptions.EnableInitTable">
+        <member name="P:Admin.NET.Core.DbConnectionOptions.ConnectionConfigs">
             <summary>
-            启用初始化库表
+            数据库集合
             </summary>
         </member>
-        <member name="P:Admin.NET.Core.DbConnectionOptions.EnableDiffLog">
+        <member name="P:Admin.NET.Core.DbConnectionConfig.EnableInitDb">
             <summary>
-            启用库表差异日志
+            启用库表初始化
             </summary>
         </member>
-        <member name="P:Admin.NET.Core.DbConnectionOptions.ConnectionConfigs">
+        <member name="P:Admin.NET.Core.DbConnectionConfig.EnableDiffLog">
             <summary>
-            数据库配置集合
+            启用库表差异日志
             </summary>
         </member>
         <member name="T:Admin.NET.Core.EmailOptions">
@@ -7478,11 +7478,10 @@
             <param name="unifyResultSettings"></param>
             <returns></returns>
         </member>
-        <member name="M:Admin.NET.Core.AdminResultProvider.RESTfulResult(Microsoft.AspNetCore.Http.HttpContext,System.Int32,System.Boolean,System.Object,System.Object)">
+        <member name="M:Admin.NET.Core.AdminResultProvider.RESTfulResult(System.Int32,System.Boolean,System.Object,System.Object)">
             <summary>
             返回 RESTful 风格结果集
             </summary>
-            <param name="context"></param>
             <param name="statusCode"></param>
             <param name="succeeded"></param>
             <param name="data"></param>
@@ -7623,6 +7622,11 @@
             <param name="path"></param>
             <returns></returns>
         </member>
+        <member name="T:Admin.NET.Core.LongJsonConverter">
+            <summary>
+            序列化时long转string(防止js精度溢出)
+            </summary>
+        </member>
         <member name="T:Admin.NET.Core.ReflectionUtil">
             <summary>
             反射工具类

+ 10 - 7
Admin.NET/Admin.NET.Core/Option/DbConnectionOptions.cs

@@ -1,22 +1,25 @@
 namespace Admin.NET.Core;
 
 /// <summary>
-/// 数据库链接配置
+/// 数据库配置选项
 /// </summary>
 public sealed class DbConnectionOptions : IConfigurableOptions
 {
     /// <summary>
-    /// 启用初始化库表
+    /// 数据库集合
     /// </summary>
-    public bool EnableInitTable { get; set; }
+    public List<DbConnectionConfig> ConnectionConfigs { get; set; }
+}
 
+public sealed class DbConnectionConfig : ConnectionConfig
+{
     /// <summary>
-    /// 启用库表差异日志
+    /// 启用库表初始化
     /// </summary>
-    public bool EnableDiffLog { get; set; }
+    public bool EnableInitDb { get; set; }
 
     /// <summary>
-    /// 数据库配置集合
+    /// 启用库表差异日志
     /// </summary>
-    public List<ConnectionConfig> ConnectionConfigs { get; set; }
+    public bool EnableDiffLog { get; set; }
 }

+ 1 - 1
Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenService.cs

@@ -318,7 +318,7 @@ public class SysCodeGenService : IDynamicApiController, ITransient
             if (list.Count > 0)
             {
                 var listIds = list.Select(f => f.Id).ToList();
-                var _ChildlistIds=new List<long>();
+                var _ChildlistIds = new List<long>();
                 foreach (var item in listIds)
                 {
                     var _Childlist = await _db.Queryable<SysMenu>().ToChildListAsync(u => u.Pid, item);

+ 19 - 19
Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs

@@ -1,5 +1,3 @@
-using DbType = SqlSugar.DbType;
-
 namespace Admin.NET.Core;
 
 public static class SqlSugarSetup
@@ -32,7 +30,7 @@ public static class SqlSugarSetup
             };
         });
 
-        SqlSugarScope sqlSugar = new(dbOptions.ConnectionConfigs, client =>
+        SqlSugarScope sqlSugar = new(dbOptions.ConnectionConfigs.Adapt<List<ConnectionConfig>>(), client =>
         {
             dbOptions.ConnectionConfigs.ForEach(config =>
             {
@@ -103,7 +101,8 @@ public static class SqlSugarSetup
                 // 差异日志
                 db.Aop.OnDiffLogEvent = async u =>
                 {
-                    if (!dbOptions.EnableDiffLog) return;
+                    if (!config.EnableDiffLog) return;
+
                     var LogDiff = new SysLogDiff
                     {
                         // 操作后记录(字段描述、列名、值、表名、表描述)
@@ -145,9 +144,8 @@ public static class SqlSugarSetup
             });
         });
 
-        // 初始化数据库结构及种子数据
-        if (dbOptions.EnableInitTable)
-            InitDataBase(sqlSugar, dbOptions);
+        // 初始化数据库表结构及种子数据
+        InitDataBase(sqlSugar, dbOptions);
 
         services.AddSingleton<ISqlSugarClient>(sqlSugar); // 单例注册
         services.AddScoped(typeof(SqlSugarRepository<>)); // 注册仓储
@@ -162,27 +160,29 @@ public static class SqlSugarSetup
         // 创建数据库
         dbOptions.ConnectionConfigs.ForEach(config =>
         {
-            if (config.DbType != DbType.Oracle)
-                db.GetConnectionScope(config.ConfigId).DbMaintenance.CreateDatabase();
+            if (!config.EnableInitDb) return;
+            if (config.DbType == SqlSugar.DbType.Oracle) return;
+            db.GetConnectionScope(config.ConfigId).DbMaintenance.CreateDatabase();
         });
 
-        // 获取所有实体表
+        // 获取所有实体表-初始化表结构
         var entityTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass
             && u.IsDefined(typeof(SugarTable), false) && !u.IsDefined(typeof(NotTableAttribute), false));
         if (!entityTypes.Any()) return;
-        // 初始化库表结构
         foreach (var entityType in entityTypes)
         {
             var tAtt = entityType.GetCustomAttribute<TenantAttribute>();
-            var provider = db.GetConnectionScope(tAtt == null ? SqlSugarConst.ConfigId : tAtt.configId);
-            provider.CodeFirst.InitTables(entityType);
+            var configId = tAtt == null ? SqlSugarConst.ConfigId : tAtt.configId.ToString();
+            if (!dbOptions.ConnectionConfigs.FirstOrDefault(u => u.ConfigId == configId.ToString()).EnableInitDb)
+                continue;
+            var db2 = db.GetConnectionScope(configId);
+            db2.CodeFirst.InitTables(entityType);
         }
 
-        // 获取所有实体种子数据
+        // 获取所有种子配置-初始化数据
         var seedDataTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass
             && u.GetInterfaces().Any(i => i.HasImplementedRawGeneric(typeof(ISqlSugarEntitySeedData<>))));
         if (!seedDataTypes.Any()) return;
-
         foreach (var seedType in seedDataTypes)
         {
             var instance = Activator.CreateInstance(seedType);
@@ -193,16 +193,16 @@ public static class SqlSugarSetup
 
             var entityType = seedType.GetInterfaces().First().GetGenericArguments().First();
             var tAtt = entityType.GetCustomAttribute<TenantAttribute>();
-            var db2 = db.GetConnectionScope(tAtt == null ? SqlSugarConst.ConfigId : tAtt.configId);
+            var configId = tAtt == null ? SqlSugarConst.ConfigId : tAtt.configId.ToString();
+            if (!dbOptions.ConnectionConfigs.FirstOrDefault(u => u.ConfigId == configId).EnableInitDb)
+                continue;
+            var db2 = db.GetConnectionScope(configId);
 
             var seedDataTable = seedData.ToList().ToDataTable();
             seedDataTable.TableName = db.EntityMaintenance.GetEntityInfo(entityType).DbTableName;
             if (seedDataTable.Columns.Contains(SqlSugarConst.PrimaryKey))
             {
                 var storage = db2.Storageable(seedDataTable).WhereColumns(SqlSugarConst.PrimaryKey).ToStorage();
-                //// 如果添加一条种子数,sqlsugar 默认以 @param 的方式赋值,如果 PropertyType 为空,则默认数据类型为字符串。插入 pgsql 时候会报错,所以要忽略为空的值添加
-                //_ = ((InsertableProvider<Dictionary<string, object>>)storage.AsInsertable).IsSingle ?
-                //    storage.AsInsertable.IgnoreColumns("UpdateTime", "UpdateUserId", "CreateUserId").ExecuteCommand() :
                 storage.AsInsertable.ExecuteCommand();
                 storage.AsUpdateable.ExecuteCommand();
             }

+ 6 - 17
Admin.NET/Admin.NET.Core/Util/AdminResultProvider.cs

@@ -14,7 +14,7 @@ public class AdminResultProvider : IUnifyResultProvider
     /// <returns></returns>
     public IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata)
     {
-        return new JsonResult(RESTfulResult(context.HttpContext, metadata.StatusCode, errors: metadata.Errors));
+        return new JsonResult(RESTfulResult(metadata.StatusCode, errors: metadata.Errors));
     }
 
     /// <summary>
@@ -25,7 +25,7 @@ public class AdminResultProvider : IUnifyResultProvider
     /// <returns></returns>
     public IActionResult OnSucceeded(ActionExecutedContext context, object data)
     {
-        return new JsonResult(RESTfulResult(context.HttpContext, StatusCodes.Status200OK, true, data));
+        return new JsonResult(RESTfulResult(StatusCodes.Status200OK, true, data));
     }
 
     /// <summary>
@@ -36,7 +36,7 @@ public class AdminResultProvider : IUnifyResultProvider
     /// <returns></returns>
     public IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata)
     {
-        return new JsonResult(RESTfulResult(context.HttpContext, metadata.StatusCode ?? StatusCodes.Status400BadRequest, errors: metadata.ValidationResult));
+        return new JsonResult(RESTfulResult(metadata.StatusCode ?? StatusCodes.Status400BadRequest, errors: metadata.ValidationResult));
     }
 
     /// <summary>
@@ -55,12 +55,12 @@ public class AdminResultProvider : IUnifyResultProvider
         {
             // 处理 401 状态码
             case StatusCodes.Status401Unauthorized:
-                await context.Response.WriteAsJsonAsync(RESTfulResult(context, statusCode, errors: "401 登录已过期,请重新登录"),
+                await context.Response.WriteAsJsonAsync(RESTfulResult(statusCode, errors: "401 登录已过期,请重新登录"),
                     App.GetOptions<JsonOptions>()?.JsonSerializerOptions);
                 break;
             // 处理 403 状态码
             case StatusCodes.Status403Forbidden:
-                await context.Response.WriteAsJsonAsync(RESTfulResult(context, statusCode, errors: "403 禁止访问,没有权限"),
+                await context.Response.WriteAsJsonAsync(RESTfulResult(statusCode, errors: "403 禁止访问,没有权限"),
                     App.GetOptions<JsonOptions>()?.JsonSerializerOptions);
                 break;
 
@@ -71,24 +71,13 @@ public class AdminResultProvider : IUnifyResultProvider
     /// <summary>
     /// 返回 RESTful 风格结果集
     /// </summary>
-    /// <param name="context"></param>
     /// <param name="statusCode"></param>
     /// <param name="succeeded"></param>
     /// <param name="data"></param>
     /// <param name="errors"></param>
     /// <returns></returns>
-    private static AdminResult<object> RESTfulResult(HttpContext context, int statusCode, bool succeeded = default, object data = default, object errors = default)
+    private static AdminResult<object> RESTfulResult(int statusCode, bool succeeded = default, object data = default, object errors = default)
     {
-        //// 获取自定义规范化结果特性
-        //var methodAttr = context.GetMetadata<CustomUnifyResultAttribute>();
-        //if (methodAttr.Name == "APP")
-        //{
-        //    return new JsonResult(new
-        //    {
-        //        AppResult = "APP返回格式"
-        //    });
-        //}
-
         return new AdminResult<object>
         {
             Code = statusCode,

+ 25 - 0
Admin.NET/Admin.NET.Core/Util/LongJsonConverter.cs

@@ -0,0 +1,25 @@
+using Newtonsoft.Json.Linq;
+
+namespace Admin.NET.Core;
+
+/// <summary>
+/// 序列化时long转string(防止js精度溢出)
+/// </summary>
+public class LongJsonConverter : JsonConverter
+{
+    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+    {
+        JToken jtoken = JValue.ReadFrom(reader);
+        return jtoken.Values();
+    }
+
+    public override bool CanConvert(Type objectType)
+    {
+        return typeof(System.Int64).Equals(objectType);
+    }
+
+    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+    {
+        serializer.Serialize(writer, value.ToString());
+    }
+}

+ 1 - 1
Admin.NET/Admin.NET.UnitTest/Admin.NET.UnitTest.csproj

@@ -8,7 +8,7 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Furion.Pure.Xunit" Version="4.4.3" />
+    <PackageReference Include="Furion.Pure.Xunit" Version="4.4.4" />
     <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.9" />
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
     <PackageReference Include="xunit" Version="2.4.2" />

+ 3 - 2
Admin.NET/Admin.NET.Web.Core/Startup.cs

@@ -46,10 +46,11 @@ public class Startup : AppStartup
             .AddAppLocalization()
             .AddNewtonsoftJson(options =>
             {
-                options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); // 响应驼峰命名
+                options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); // 首字母小写(驼峰样式)
                 options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; // 时间格式化
                 options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // 忽略循环引用
-                // options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; // 忽略空值
+                options.SerializerSettings.Converters.Add(new LongJsonConverter()); // long转string(防止js精度溢出)
+                options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; // 忽略空值
             })
             .AddInjectWithUnifyResult<AdminResultProvider>();