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
{
///
/// MySQL 数据库复制工具类
///
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;
}
///
/// 获取数据库列表
///
public static List GetDatabases(ISqlSugarClient db)
{
var all = db.Ado.SqlQuery("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(@"
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 logs)
{
//db.Ado.ExecuteCommand($"USE `{source}`");
var tables = db.Ado.SqlQuery($"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($"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 logs)
{
var views = db.Ado.SqlQuery(
"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($"USE `{source}`;SHOW CREATE VIEW `{view}`;");
//var row = db.Ado.SqlQuerySingle($"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 logs)
{
var routines = db.Ado.SqlQuery(
"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($"USE `{source}`;SHOW CREATE {type} `{routine}`;");
// var row = db.Ado.SqlQuerySingle($"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 logs)
{
var triggers = db.Ado.SqlQuery(
"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($"USE `{source}`;SHOW CREATE TRIGGER `{trigger}`;");
//var row = db.Ado.SqlQuerySingle($"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;
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 Logs { get; set; } = new();
}
}