Initial_commit_SecMPS_v2

This commit is contained in:
2026-05-15 23:22:48 +08:00
commit 23ea4fe05f
13830 changed files with 298675 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.DBManager
{
public class DBConnectionAttribute : Attribute
{
public string DBName { get; set; }
}
}

View File

@@ -0,0 +1,138 @@
using Microsoft.EntityFrameworkCore;
using Npgsql;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using VolPro.Core.Configuration;
using VolPro.Core.Const;
using VolPro.Core.Dapper;
using VolPro.Core.EFDbContext;
using VolPro.Core.Enums;
using VolPro.Core.Extensions;
using MySqlConnector;
using VolPro.Core.ManageUser;
using VolPro.Entity.SystemModels;
using VolPro.Entity;
using Microsoft.Extensions.DependencyModel;
using System.Reflection;
using System.Runtime.Loader;
using System.Linq;
using Oracle.ManagedDataAccess.Client;
using VolPro.Core.DbSqlSugar;
using SqlSugar;
using VolPro.Core.CacheManager;
namespace VolPro.Core.DBManager
{
public partial class DBServerProvider : DbManger
{
////系统库
private static readonly string DefaultConnName = nameof(SysDbContext);
static DBServerProvider()
{
}
public static void SetConnection(string key, string val)
{
DbRelativeCache.DbContextConnection[key] = val;
}
public static string GetConnectionString(string key)
{
return DbRelativeCache.DbContextConnection[key ?? DefaultConnName];
}
/// <summary>
/// 获取系统库
/// </summary>
public static SysDbContext DbContext
{
get
{
SysDbContext dbContext = Utilities.HttpContext.Current.RequestServices.GetService(typeof(SysDbContext)) as SysDbContext;
return dbContext;
}
}
/// <summary>
/// 根据实体model获取对应EF
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <returns></returns>
public static BaseDbContext GetEntityDbContext<TEntity>()
{
string dbServer = typeof(TEntity).GetTypeCustomValue<EntityAttribute>(x => x.DBServer);
return Utilities.HttpContext.Current.RequestServices.GetService(DbRelativeCache.GetDbContextType(dbServer)) as BaseDbContext;
}
/// <summary>
/// 指定获取数据库
/// </summary>
/// <param name="dbService"></param>
/// <returns></returns>
public static string GetDbEntityName(string dbServer)
{
return DbRelativeCache.GetDbEntityType(dbServer).Name;
}
//public static ISqlSugarClient GetSqlSugarClient(string connectionKey = null)
//{
// return DbManger.GetConnection(connectionKey);
//}
/// <summary>
/// 根据dbcontext名称获取数据库链接
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static string GetDbConnectionString(string key)
{
if (DbRelativeCache.DbContextConnection.TryGetValue(key, out string connString))
{
return connString;
}
throw new Exception($"未配置[{key}]的数据库连接");
}
public static string GetDbConnectionString(Type dbContext)
{
return GetDbConnectionString(dbContext.Name);
}
/// <summary>
/// 获取系统库的字符串连接
/// </summary>
public static string SysConnectingString
{
get { return GetDbConnectionString(DefaultConnName); }
}
/// <summary>
/// 获取业务库的字符串连接
/// </summary>
public static string ServiceConnectingString
{
get
{
//动态无限分库获取用户当前选择的数据库
if (AppSetting.UseDynamicShareDB)
{
return GetDbConnectionString(UserContext.CurrentServiceId.ToString());
}
return GetDbConnectionString(nameof(ServiceDbContext));
}
}
/// <summary>
/// 动态租户分库获取指定数据库id的链接(2023.11.05)
/// </summary>
/// <param name="serviceId"></param>
/// <returns></returns>
public static string GetServiceConnectingString(Guid serviceId)
{
return DbRelativeCache.DbContextConnection[serviceId.ToString()];
}
}
}

View File

@@ -0,0 +1,284 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using VolPro.Core.Extensions;
using VolPro.Core.Services;
using VolPro.Core.Utilities;
namespace VolPro.Core.DbManager.DbCopy
{
/// <summary>
/// MySQL 数据库复制工具类
/// </summary>
public class DbCopyMysql
{
public static WebResponseContent CopyDatabase(ISqlSugarClient db,ISqlSugarClient toDbContext, string sourceDatabase,
string targetDatabase, bool includeData = true)
{
var result = new CopyResult();
var logs = result.Logs;
try
{
// 验证
if (string.IsNullOrWhiteSpace(sourceDatabase))
throw new ArgumentException("源数据库名不能为空");
if (string.IsNullOrWhiteSpace(targetDatabase))
throw new ArgumentException("目标数据库名不能为空");
if (sourceDatabase.Equals(targetDatabase, StringComparison.OrdinalIgnoreCase))
throw new ArgumentException("源和目标数据库不能相同");
logs.Add($"[{DateTime.Now:HH:mm:ss}] 开始复制: {sourceDatabase} -> {targetDatabase}");
// 检查源数据库
if (!DbExists(db, sourceDatabase))
throw new Exception($"源数据库 '{sourceDatabase}' 不存在");
// 检查目标数据库
if (DbExists(db, targetDatabase))
throw new Exception($"目标数据库 '{targetDatabase}' 已存在");
// 创建目标数据库
logs.Add($"[{DateTime.Now:HH:mm:ss}] 创建目标数据库...");
CreateDb(db, sourceDatabase, targetDatabase);
// 复制表
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制表...");
CopyTables(db,toDbContext, sourceDatabase, targetDatabase, includeData, result, logs);
// 复制视图
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制视图...");
result.ViewsCount = CopyViews(db,toDbContext, sourceDatabase, targetDatabase, logs);
// 复制存储过程
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制存储过程...");
result.ProceduresCount = CopyRoutines(db, toDbContext, sourceDatabase, targetDatabase, "PROCEDURE", logs);
// 复制函数
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制函数...");
result.FunctionsCount = CopyRoutines(db,toDbContext, sourceDatabase, targetDatabase, "FUNCTION", logs);
// 复制触发器
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制触发器...");
result.TriggersCount = CopyTriggers(db, sourceDatabase, targetDatabase, logs);
result.Success = true;
result.Message = "复制成功";
logs.Add($"[{DateTime.Now:HH:mm:ss}] ✓ 完成! 表:{result.TablesCount} 视图:{result.ViewsCount} " +
$"存储过程:{result.ProceduresCount} 函数:{result.FunctionsCount} 触发器:{result.TriggersCount} " +
$"行数:{result.TotalRowsCopied} 耗时:{result.ElapsedSeconds:F2}秒");
}
catch (Exception ex)
{
result.Success = false;
result.Message = ex.Message;
logs.Add($"[{DateTime.Now:HH:mm:ss}] ✗ 错误: {ex.Message}");
}
WebResponseContent webResponse = new WebResponseContent();
webResponse.Status = result.Success;
webResponse.Message = result.Message;
Logger.Info($"mysql创建数据库{logs.Serialize()}");
return webResponse;
}
/// <summary>
/// 获取数据库列表
/// </summary>
public static List<string> GetDatabases(ISqlSugarClient db)
{
var all = db.Ado.SqlQuery<string>("SHOW DATABASES");
var system = new[] { "information_schema", "mysql", "performance_schema", "sys" };
return all.Where(x => !system.Contains(x.ToLower())).ToList();
}
private static bool DbExists(ISqlSugarClient db, string name)
{
return db.Ado.GetInt(
"SELECT COUNT(*) FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @name",
new { name }) > 0;
}
private static void CreateDb(ISqlSugarClient db, string source, string target)
{
var info = db.Ado.SqlQuerySingle<dynamic>(@"
SELECT DEFAULT_CHARACTER_SET_NAME AS Charset, DEFAULT_COLLATION_NAME AS Collation
FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @name", new { name = source });
var charset = info?.Charset ?? "utf8mb4";
var collation = info?.Collation ?? "utf8mb4_general_ci";
db.Ado.ExecuteCommand($"CREATE DATABASE `{target}` CHARACTER SET {charset} COLLATE {collation}");
}
private static void CopyTables(ISqlSugarClient db, ISqlSugarClient toDbContext, string source, string target,
bool includeData, CopyResult result, List<string> logs)
{
//db.Ado.ExecuteCommand($"USE `{source}`");
var tables = db.Ado.SqlQuery<string>($"USE `{source}`;SHOW TABLES;");
db.Ado.ExecuteCommand($"USE `{target}`");
db.Ado.ExecuteCommand("SET FOREIGN_KEY_CHECKS = 0");
foreach (var table in tables)
{
try
{
// 获取建表语句
//db.Ado.ExecuteCommand($"USE `{source}`");
var row = db.Ado.SqlQuerySingle<dynamic>($"USE `{source}`;SHOW CREATE TABLE `{table}`");
var sql = GetValue(row, "Create Table");
if (string.IsNullOrEmpty(sql)) continue;
//创建表
toDbContext.Ado.ExecuteCommand($"USE `{target}`");
toDbContext.Ado.ExecuteCommand(sql);
result.TablesCount++;
logs.Add($" ✓ {table}");
// 复制数据
if (includeData)
{
var rows = db.Ado.ExecuteCommand(
$"INSERT INTO `{target}`.`{table}` SELECT * FROM `{source}`.`{table}`");
result.TotalRowsCopied += rows;
if (rows > 0) logs.Add($" {rows} 行");
}
}
catch (Exception ex)
{
logs.Add($" ✗ {table}: {ex.Message}");
}
}
db.Ado.ExecuteCommand("SET FOREIGN_KEY_CHECKS = 1");
}
private static int CopyViews(ISqlSugarClient db, ISqlSugarClient toDbContext, string source, string target, List<string> logs)
{
var views = db.Ado.SqlQuery<string>(
"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA = @db",
new { db = source });
var count = 0;
foreach (var view in views)
{
try
{
//db.Ado.ExecuteCommand($"USE `{source}`");
var row = db.Ado.SqlQuerySingle<dynamic>($"USE `{source}`;SHOW CREATE VIEW `{view}`;");
//var row = db.Ado.SqlQuerySingle<dynamic>($"SHOW CREATE VIEW `{view}`;");
var sql = GetValue(row, "Create View");
if (string.IsNullOrEmpty(sql)) continue;
sql = sql.Replace($"`{source}`.", $"`{target}`.");
sql = Regex.Replace(sql, @"DEFINER=`[^`]+`@`[^`]+`\s*", "");
toDbContext.Ado.ExecuteCommand($"USE `{target}`");
toDbContext.Ado.ExecuteCommand(sql);
count++;
logs.Add($" ✓ {view}");
}
catch (Exception ex)
{
logs.Add($" ✗ {view}: {ex.Message}");
}
}
return count;
}
private static int CopyRoutines(ISqlSugarClient db, ISqlSugarClient toDbContext, string source, string target,
string type, List<string> logs)
{
var routines = db.Ado.SqlQuery<string>(
"SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = @db AND ROUTINE_TYPE = @type",
new { db = source, type });
var count = 0;
var key = type == "PROCEDURE" ? "Create Procedure" : "Create Function";
foreach (var routine in routines)
{
try
{
//db.Ado.ExecuteCommand($"USE `{source}`");
var row = db.Ado.SqlQuerySingle<dynamic>($"USE `{source}`;SHOW CREATE {type} `{routine}`;");
// var row = db.Ado.SqlQuerySingle<dynamic>($"SHOW CREATE {type} `{routine}`;");
var sql = GetValue(row, key);
if (string.IsNullOrEmpty(sql)) continue;
sql = Regex.Replace(sql, @"DEFINER=`[^`]+`@`[^`]+`\s*", "");
toDbContext.Ado.ExecuteCommand($"USE `{target}`");
toDbContext.Ado.ExecuteCommand(sql);
count++;
logs.Add($" ✓ {routine}");
}
catch (Exception ex)
{
logs.Add($" ✗ {routine}: {ex.Message}");
}
}
return count;
}
private static int CopyTriggers(ISqlSugarClient db, string source, string target, List<string> logs)
{
var triggers = db.Ado.SqlQuery<string>(
"SELECT TRIGGER_NAME FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_SCHEMA = @db",
new { db = source });
var count = 0;
foreach (var trigger in triggers)
{
try
{
//db.Ado.ExecuteCommand($"USE `{source}`");
var row = db.Ado.SqlQuerySingle<dynamic>($"USE `{source}`;SHOW CREATE TRIGGER `{trigger}`;");
//var row = db.Ado.SqlQuerySingle<dynamic>($"SHOW CREATE TRIGGER `{trigger}`;");
var sql = GetValue(row, "SQL Original Statement");
if (string.IsNullOrEmpty(sql)) continue;
sql = Regex.Replace(sql, @"DEFINER=`[^`]+`@`[^`]+`\s*", "");
db.Ado.ExecuteCommand($"USE `{target}`");
db.Ado.ExecuteCommand(sql);
count++;
logs.Add($" ✓ {trigger}");
}
catch (Exception ex)
{
logs.Add($" ✗ {trigger}: {ex.Message}");
}
}
return count;
}
private static string GetValue(dynamic row, string key)
{
if (row == null) return "";
var dict = row as IDictionary<string, object>;
return dict?.ContainsKey(key) == true ? dict[key]?.ToString() ?? "" : "";
}
}
public class CopyResult
{
public bool Success { get; set; }
public string Message { get; set; } = "";
public int TablesCount { get; set; }
public int ViewsCount { get; set; }
public int ProceduresCount { get; set; }
public int FunctionsCount { get; set; }
public int TriggersCount { get; set; }
public long TotalRowsCopied { get; set; }
public double ElapsedSeconds { get; set; }
public List<string> Logs { get; set; } = new();
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.Configuration;
namespace VolPro.Core.DbManager.DbCopy
{
public class DbCopySqlserver
{
public static string CopyDatabase(string dbEmpty, string dbName)
{
string DBPath = AppSetting.GetSettingString("DBPath");
string DBBackPath = AppSetting.GetSettingString("DBBackPath");
string sql = @$"USE [master]
CREATE DATABASE [{dbName}]
CONTAINMENT = NONE
ON PRIMARY
( NAME = N'{dbName}', FILENAME = N'{DBPath}\{dbName}.mdf' , SIZE = 5120KB , FILEGROWTH = 1024KB )
LOG ON
( NAME = N'{dbName}_log', FILENAME = N'{DBPath}\{dbName}_log.ldf' , SIZE = 2048KB , FILEGROWTH = 10%)
USE [master]
BACKUP DATABASE [{dbEmpty}] TO DISK = N'{DBBackPath}\{dbEmpty}.bak' WITH COPY_ONLY, NOFORMAT, INIT,
NAME = N'{dbEmpty}', SKIP, NOREWIND, NOUNLOAD, STATS = 10
--还原数据库
DECLARE @tomdf NVARCHAR(50)=N'{DBPath}\{dbName}.mdf'
DECLARE @tolog NVARCHAR(50)=N'{DBPath}\{dbName}.ldf'
RESTORE DATABASE [{dbName}] FROM DISK = N'{DBBackPath}\{dbEmpty}.bak' WITH FILE = 1,
MOVE N'{dbEmpty}' TO @tomdf, MOVE N'{dbEmpty}_log' TO @tolog, NOUNLOAD, REPLACE, STATS = 5;
alter database {dbName} modify file(name={dbEmpty}, newname={dbName});
alter database {dbName} modify file(name={dbEmpty}_log, newname={dbName}_log) ";
return sql;
}
}
}

View File

@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.DBManage
{
public struct DbName
{
public static string Default = "default";
}
}

View File

@@ -0,0 +1,156 @@
using Microsoft.Extensions.DependencyModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using VolPro.Core.Configuration;
using VolPro.Core.Const;
using VolPro.Core.EFDbContext;
using VolPro.Core.ManageUser;
using VolPro.Entity.SystemModels;
namespace VolPro.Core.DBManager
{
public static class DbRelativeCache
{
private static Dictionary<string, Type> DbContextTypes = new Dictionary<string, Type>();
private static Dictionary<string, Type> DbEntityTypes = new Dictionary<string, Type>();
private static Dictionary<string, string> DbTypes = new Dictionary<string, string>();
/// <summary>
/// 所有数据库链接字符串
/// </summary>
private static Dictionary<string, string> DbConnection = new Dictionary<string, string>();
public static Dictionary<string, string> DbContextConnection
{
get { return DbConnection; }
}
static DbRelativeCache()
{
InitDbContextType();
InitDbEntityType();
}
/// <summary>
/// 缓存分库DbContext
/// </summary>
public static void InitDbContextType()
{
var compilationLibrary = DependencyContext
.Default
.RuntimeLibraries
.Where(x => x.Name.EndsWith(".Core") && !x.Serviceable && x.Type != "package" && x.Type == "project");
foreach (var _compilation in compilationLibrary)
{
//加载指定类
foreach (var item in AssemblyLoadContext.Default
.LoadFromAssemblyName(new AssemblyName(_compilation.Name))
.GetTypes().Where(x => x.GetTypeInfo().BaseType != null
&& x.BaseType == (typeof(BaseDbContext))))
{
DbContextTypes[item.Name] = item;
//获取数据库链接类型,在appsettings.json中Connection属性添加xxxDbType前缀与数据库链接一样
//ServiceDbContext:"数据库链接字符"=>ServiceDbType:"MsSql";数据库链接类型
string typeName = item.Name.Replace("DbContext", "").Replace("Entity", "") + "DbType";
string dbType = AppSetting.GetSection("Connection")[typeName];
DbTypes[item.Name] = dbType ?? DBType.Name;
//缓存数据库链接
string connectionString = AppSetting.GetSection("Connection")[item.Name];
DbConnection.TryAdd(item.Name, connectionString);
}
}
//缓存系统数据库链接
DbConnection[nameof(SysDbContext)] = AppSetting.GetSection("Connection")["DbConnectionString"];
}
/// <summary>
/// 缓存分库model基类
/// </summary>
public static void InitDbEntityType()
{
var compilationLibrary = DependencyContext
.Default
.RuntimeLibraries
.Where(x => x.Name.EndsWith(".Entity") && !x.Serviceable && x.Type != "package" && x.Type == "project");
foreach (var _compilation in compilationLibrary)
{
//加载指定类
foreach (var item in AssemblyLoadContext.Default
.LoadFromAssemblyName(new AssemblyName(_compilation.Name))
.GetTypes().Where(x => x.GetTypeInfo().BaseType != null
&& x.BaseType == (typeof(BaseEntity))))
{
DbEntityTypes[item.Name] = item;
}
}
}
/// <summary>
/// 获取数据库的链接类型。如数据库是mysql还是pgsql类型
/// </summary>
/// <param name="dbService"></param>
/// <returns></returns>
public static string GetDbType(string dbService)
{
if (string.IsNullOrEmpty(dbService))
{
return null;
}
DbTypes.TryGetValue(dbService, out string value);
return value;
}
/// <summary>
/// 根据分库名称获取dbcontext
/// </summary>
/// <param name="dbService"></param>
/// <returns></returns>
public static Type GetDbContextType(string dbService)
{
return DbContextTypes[dbService];
}
/// <summary>
/// 根据分库名称获取分库model基类
/// </summary>
/// <param name="dbService"></param>
/// <returns></returns>
public static Type GetDbEntityType(string dbService)
{
Type dbContextType = DbContextTypes[dbService];
string name = dbContextType.Name.Replace("DbContext", "");
return DbEntityTypes[$"{name}Entity"];
}
/// <summary>
/// 根据dbtype获取数据库链接
/// </summary>
/// <param name="dbContextType"></param>
/// <returns></returns>
public static string GetDbConnectionString(Type dbContextType)
{
return GetDbConnectionString(dbContextType.GetType().Name);
}
/// <summary>
/// 根据dbtype获取数据库链接
/// </summary>
/// <param name="dbContextType"></param>
/// <returns></returns>
public static string GetDbConnectionString(string dbContextType)
{
if (dbContextType == null)
{
return null;
}
DbConnection.TryGetValue(dbContextType, out string value);
if (dbContextType == nameof(ServiceDbContext))
{
if (AppSetting.UseDynamicShareDB)
{
return DBServerProvider.GetDbConnectionString(UserContext.CurrentServiceId.ToString());
}
}
return value;
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
using VolPro.Core.Configuration;
using VolPro.Core.Dapper;
using VolPro.Core.Enums;
namespace VolPro.Core.DBManager
{
public partial class DBServerProvider
{
}
}