822 lines
30 KiB
C#
822 lines
30 KiB
C#
using Learun.Application.TwoDevelopment.ZZDT_EC;
|
||
using MySql.Data.MySqlClient;
|
||
using SqlSugar;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Collections.Specialized;
|
||
using System.ComponentModel;
|
||
using System.Configuration;
|
||
using System.Diagnostics;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Text.RegularExpressions;
|
||
using System.Threading.Tasks;
|
||
using System.Windows;
|
||
using System.Windows.Controls;
|
||
using System.Windows.Data;
|
||
using System.Windows.Documents;
|
||
using System.Windows.Documents.DocumentStructures;
|
||
using System.Windows.Input;
|
||
using System.Windows.Media;
|
||
using System.Windows.Media.Imaging;
|
||
using System.Windows.Navigation;
|
||
using System.Windows.Shapes;
|
||
using System.Xml.Linq;
|
||
using System.Xml.Schema;
|
||
using Path = System.IO.Path;
|
||
|
||
namespace SWSDBSchemeUpgradeTool
|
||
{
|
||
/// <summary>
|
||
/// Interaction logic for MainWindow.xaml
|
||
/// </summary>
|
||
public partial class MainWindow : Window, INotifyPropertyChanged
|
||
{
|
||
public event PropertyChangedEventHandler PropertyChanged;
|
||
#region binding
|
||
private string _configPath;
|
||
|
||
|
||
|
||
public string configPath
|
||
{
|
||
get { return _configPath; }
|
||
set
|
||
{
|
||
_configPath = value;
|
||
}
|
||
}
|
||
|
||
private string _basedb;
|
||
|
||
public string basedb
|
||
{
|
||
get { return _basedb; }
|
||
set { _basedb = value; }
|
||
}
|
||
|
||
|
||
private string _curVersion;
|
||
|
||
public string curVersion
|
||
{
|
||
get { return _curVersion; }
|
||
set { _curVersion = value; }
|
||
}
|
||
#endregion
|
||
private string dbName = "";
|
||
/// <summary>
|
||
/// 是否被初始化过。没有的话,就要去执行sws.sql。
|
||
/// </summary>
|
||
private bool bInitialed;
|
||
/// <summary>
|
||
/// (iis文件夹根目录)
|
||
/// </summary>
|
||
private string IISDirectory;
|
||
/// <summary>
|
||
/// exe的目录,会带一个\在后面
|
||
/// </summary>
|
||
private string baseDirectory;
|
||
|
||
string logFileName = "sync_errors.log";
|
||
string Initial_Data_sql = "Initial_Data.sql";
|
||
public MainWindow()
|
||
{
|
||
|
||
InitializeComponent();
|
||
ContentGrid.DataContext = this;
|
||
|
||
|
||
ReadDBConfig();
|
||
ConnDB();
|
||
IfInitialed();
|
||
|
||
|
||
|
||
}
|
||
/// <summary>
|
||
/// 读取database.config文件
|
||
/// </summary>
|
||
private void ReadDBConfig()
|
||
{
|
||
baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
|
||
// 获取上一级目录(iis文件夹根目录)
|
||
IISDirectory = Directory.GetParent(baseDirectory.TrimEnd(Path.DirectorySeparatorChar)).FullName;
|
||
|
||
configPath = IISDirectory + "/XmlConfig/" + "database.config";
|
||
if (System.IO.File.Exists(configPath))
|
||
{
|
||
XDocument xDoc = XDocument.Load(configPath);
|
||
var node = xDoc.Descendants("connectionStrings").Elements("add").FirstOrDefault();
|
||
if (node == null)
|
||
{
|
||
//不存在
|
||
MessageBox.Show("未能在database.config中的connectionStrings - add路径下找到合法的connectionString属性。请确认!");
|
||
Application.Current.Shutdown();
|
||
}
|
||
basedb = node.Attribute("connectionString").Value;
|
||
}
|
||
else
|
||
{
|
||
//不存在
|
||
MessageBox.Show("未能在同目录XmlConfig文件夹下找到database.config文件。请确认!");
|
||
Application.Current.Shutdown();
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 连接到数据库
|
||
/// </summary>
|
||
private void ConnDB()
|
||
{
|
||
SqlSugarHelper.Db = new SqlSugarScope(new ConnectionConfig()
|
||
{
|
||
ConfigId = "0",
|
||
ConnectionString = basedb,//连接符字串
|
||
DbType = DbType.MySql,//数据库类型
|
||
IsAutoCloseConnection = true //不设成true要手动close
|
||
},
|
||
db =>
|
||
{
|
||
//(A)全局生效配置点,一般AOP和程序启动的配置扔这里面 ,所有上下文生效
|
||
//调试SQL事件,可以删掉
|
||
db.Aop.OnLogExecuting = (sql, pars) =>
|
||
{
|
||
|
||
//获取原生SQL推荐 5.1.4.63 性能OK
|
||
Console.WriteLine(UtilMethods.GetNativeSql(sql, pars));
|
||
|
||
//获取无参数化SQL 对性能有影响,特别大的SQL参数多的,调试使用
|
||
//Console.WriteLine(UtilMethods.GetSqlString(DbType.SqlServer,sql,pars))
|
||
|
||
};
|
||
|
||
//多个配置就写下面
|
||
//db.Ado.IsDisableMasterSlaveSeparation=true;
|
||
|
||
//注意多租户 有几个设置几个
|
||
//db.GetConnection(i).Aop
|
||
});
|
||
|
||
|
||
|
||
// 尝试找到database=的部分
|
||
int startIndex = basedb.IndexOf("database=");
|
||
if (startIndex != -1)
|
||
{
|
||
// 查找下一个分号的位置,以分割出database的值
|
||
int endIndex = basedb.IndexOf(";", startIndex);
|
||
if (endIndex == -1)
|
||
{
|
||
// 如果没有找到分号,则取字符串的剩余部分
|
||
endIndex = basedb.Length;
|
||
}
|
||
|
||
// 提取database的值
|
||
dbName = basedb.Substring(startIndex + "database=".Length, endIndex - startIndex - "database=".Length);
|
||
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show("Database name not found in the connect string.请确认!");
|
||
Application.Current.Shutdown();
|
||
}
|
||
}
|
||
|
||
private void IfInitialed()
|
||
{
|
||
|
||
var temp = SqlSugarHelper.Db.Ado.GetDataTable($@"SELECT
|
||
*
|
||
FROM
|
||
information_schema.TABLES
|
||
WHERE
|
||
TABLE_SCHEMA = '{dbName}' AND
|
||
TABLE_NAME = 'ec_business_table';");
|
||
|
||
if (temp.Rows.Count > 0)
|
||
{
|
||
curVersion = $"数据库名:{dbName}";
|
||
bInitialed = true;
|
||
}
|
||
else
|
||
{
|
||
curVersion = "当前数据库还未初始化!";
|
||
bInitialed = false;
|
||
}
|
||
|
||
|
||
|
||
}
|
||
|
||
|
||
void ExecuteVersionedScripts(string scriptsBasePath)
|
||
{
|
||
// 获取所有版本文件夹,并按版本顺序排序
|
||
var versionFolders = Directory.GetDirectories(scriptsBasePath)
|
||
.OrderBy(v => v)
|
||
.ToList();
|
||
|
||
foreach (var versionFolder in versionFolders)
|
||
{
|
||
//分sub和nonsub2个子文件夹
|
||
// 获取版本号
|
||
string version = new DirectoryInfo(versionFolder).Name;
|
||
|
||
var subFolders = Directory.GetDirectories(Path.Combine(scriptsBasePath, version)).ToList();
|
||
foreach (var subFolder in subFolders)
|
||
{
|
||
// 获取该版本文件夹下的所有脚本
|
||
string[] sqlFiles = Directory.GetFiles(subFolder, "*.sql").OrderBy(f => f).ToArray();
|
||
|
||
string subFolderName = new DirectoryInfo(subFolder).Name;
|
||
bool ProjectRelated = true;
|
||
if (subFolderName.ToLower().Contains("no"))
|
||
{
|
||
//和Project无关
|
||
ProjectRelated = false;
|
||
}
|
||
else
|
||
{
|
||
ProjectRelated = true;
|
||
//和Project相关
|
||
}
|
||
// 检查该版本的所有脚本是否都已执行
|
||
if (!AreAllScriptsExecuted(version, sqlFiles))
|
||
{
|
||
foreach (var file in sqlFiles)
|
||
{
|
||
string scriptName = System.IO.Path.GetFileName(file);
|
||
|
||
// 如果该脚本未执行,则执行它
|
||
if (!IsScriptExecuted(version, scriptName))
|
||
{
|
||
string sql = File.ReadAllText(file);
|
||
//using MySqlCommand cmd = new MySqlCommand(sql, conn);
|
||
//cmd.ExecuteNonQuery();
|
||
|
||
|
||
try
|
||
{
|
||
CompareSchemas2(sql, ProjectRelated, scriptName);
|
||
// 记录该脚本的执行
|
||
RecordScriptExecution(version, scriptName);
|
||
}
|
||
catch (MySqlException ex)
|
||
{
|
||
LogError(baseDirectory + logFileName, ex, sql);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
static void LogError(string logFilePath, MySqlException ex, string info)
|
||
{
|
||
StreamWriter log = new StreamWriter(logFilePath, append: true);
|
||
log.WriteLine("Timestamp: " + DateTime.Now);
|
||
log.WriteLine("SQL Error Number: " + ex.Number);
|
||
log.WriteLine("Error Message: " + ex.Message);
|
||
log.WriteLine("SQL involved: " + info);
|
||
log.WriteLine("---------------------------------------------------");
|
||
log.Close();
|
||
}
|
||
static void LogInfo(string logFilePath, string info)
|
||
{
|
||
StreamWriter log = new StreamWriter(logFilePath, append: true);
|
||
log.WriteLine("Timestamp: " + DateTime.Now);
|
||
log.WriteLine("Warning Message: " + info);
|
||
log.WriteLine("---------------------------------------------------");
|
||
log.Close();
|
||
}
|
||
|
||
|
||
// 检查版本下的所有脚本是否都已执行
|
||
bool AreAllScriptsExecuted(string version, string[] sqlFiles)
|
||
{
|
||
foreach (var file in sqlFiles)
|
||
{
|
||
string scriptName = System.IO.Path.GetFileName(file);
|
||
if (!IsScriptExecuted(version, scriptName))
|
||
{
|
||
return false; // 如果有一个脚本未执行,则返回false
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// 检查单个脚本是否已执行
|
||
bool IsScriptExecuted(string version, string scriptName)
|
||
{
|
||
string query = $"SELECT COUNT(1) FROM SchemaVersion WHERE Version = '{version}' AND ScriptName = '{scriptName}';";
|
||
//using MySqlCommand cmd = new MySqlCommand(query, conn);
|
||
//cmd.Parameters.AddWithValue("@Version", version);
|
||
//cmd.Parameters.AddWithValue("@ScriptName", scriptName);
|
||
var temp = SqlSugarHelper.Db.Ado.GetDataTable(query);
|
||
return Convert.ToInt32(temp.Rows[0][0]) > 0;
|
||
}
|
||
|
||
// 记录脚本执行情况
|
||
void RecordScriptExecution(string version, string scriptName)
|
||
{
|
||
string query = $"INSERT INTO SchemaVersion (Version, ScriptName, UpdateTime) VALUES ('{version}', '{scriptName}', NOW());";
|
||
//using MySqlCommand cmd = new MySqlCommand(query, conn);
|
||
//cmd.Parameters.AddWithValue("@Version", version);
|
||
//cmd.Parameters.AddWithValue("@ScriptName", scriptName);
|
||
//cmd.ExecuteNonQuery();
|
||
SqlSugarHelper.Db.Ado.ExecuteCommand(query);
|
||
}
|
||
/// <summary>
|
||
/// 增补更新。去找SQL文件夹下,每个小sql的内容
|
||
/// </summary>
|
||
/// <param name="sender"></param>
|
||
/// <param name="e"></param>
|
||
private void Button_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
if (bInitialed)
|
||
{
|
||
if (!Directory.Exists(IISDirectory + "/" + "SQL"))
|
||
{
|
||
MessageBox.Show($"IIS根目录({IISDirectory})下的SQL文件夹不存在。请检查。");
|
||
return;
|
||
}
|
||
ExecuteVersionedScripts(IISDirectory + "/" + "SQL");
|
||
}
|
||
|
||
MessageBox.Show("SQL synchronization completed. Please check the log file for any errors: " + baseDirectory + logFileName);
|
||
|
||
}
|
||
private async Task UpdateProgress(string content, int value)
|
||
{
|
||
StatusText.Content = content;
|
||
ProgressBar.Value = value;
|
||
await Task.Delay(200); // Simulating work
|
||
|
||
}
|
||
private async Task UpdateText(string content)
|
||
{
|
||
StatusText2.Text = content.Replace("\n", " ");
|
||
|
||
}
|
||
private async void Button_Click_1(object sender, RoutedEventArgs e)
|
||
{
|
||
await UpdateProgress("开始解析原始SQL脚本。。。", 20);
|
||
var allSqlTb = ExtractTables();
|
||
await UpdateProgress("开始查询当前数据库内的状态。。。", 20);
|
||
var allDbTb = GetDatabaseTableStructures();
|
||
await UpdateProgress("开始比较SQL脚本和数据库的差异。。。", 40);
|
||
var diffcontent = CompareSchemas(allSqlTb, allDbTb);
|
||
await UpdateProgress("开始生成需要的SQL语句。。。", 60);
|
||
var fixedSQL = GenerateFixSql(diffcontent, allSqlTb);
|
||
await UpdateProgress("SQL语句已准备好,请预览。。。", 80);
|
||
//预览
|
||
SQLPreview secondWindow = new SQLPreview(fixedSQL);
|
||
secondWindow.ShowDialog();
|
||
var chooseRes = MessageBox.Show("是否要开始进行SQL语句?", "询问", MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||
if (chooseRes == MessageBoxResult.Yes)
|
||
{
|
||
await UpdateProgress("开始进行SQL语句执行。。。", 90);
|
||
await ExecuteComparisonSQL(fixedSQL);
|
||
await UpdateProgress("完成。", 100);
|
||
MessageBox.Show("Initial Database Structure comparison completed. Please check the log file for any errors: ");
|
||
}
|
||
else
|
||
{
|
||
|
||
}
|
||
|
||
await UpdateProgress("", 0);
|
||
}
|
||
/// <summary>
|
||
/// 解析、抽取初始脚本的SQL(表)
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
List<Table> ExtractTables()
|
||
{
|
||
string sqlFilePath = IISDirectory + "/" + "SQL" + "/" + Initial_Data_sql; // Update with the correct file path
|
||
string sqlContent = File.ReadAllText(sqlFilePath);
|
||
var tables = new List<Table>();
|
||
|
||
// Match each CREATE TABLE statement
|
||
string tablePattern = @"CREATE\s+TABLE\s+`?(?<TableName>\w+)`?\s*\((?<Columns>[\s\S]*?)\)\s*ENGINE";
|
||
var tableMatches = Regex.Matches(sqlContent, tablePattern);
|
||
|
||
foreach (Match tableMatch in tableMatches)
|
||
{
|
||
var tableName = tableMatch.Groups["TableName"].Value;
|
||
var columnsDefinition = tableMatch.Groups["Columns"].Value;
|
||
|
||
var table = new Table
|
||
{
|
||
Name = tableName,
|
||
Columns = ExtractColumns(columnsDefinition)
|
||
};
|
||
|
||
tables.Add(table);
|
||
}
|
||
|
||
return tables;
|
||
}
|
||
/// <summary>
|
||
/// 解析、抽取初始脚本的SQL(表中的列)
|
||
/// </summary>
|
||
/// <param name="columnsDefinition"></param>
|
||
/// <returns></returns>
|
||
public static List<ColumnInfo> ExtractColumns(string columnsDefinition)
|
||
{
|
||
var columns = new List<ColumnInfo>();
|
||
//string columnPattern = @"`(?<ColumnName>\w+)`\s+(?<DataType>\w+\(\d+\))\s+(CHARACTER\s+SET\s+\w+\s+COLLATE\s+\w+\s+)?(?<Nullability>NOT\s+NULL|NULL)";
|
||
string columnPattern = @"`(?<ColumnName>\w+)`\s+(?<DataType>\w+(\(\d+\))?)(\s+CHARACTER\s+SET\s+\w+\s+COLLATE\s+\w+)?\s+(?<Nullability>NOT\s+NULL|NULL)";
|
||
|
||
// Match each column definition inside the CREATE TABLE statement
|
||
// string columnPattern = @"`(?<column>\w+)`\s+\w+";// @"`(?<ColumnName>\w+)`\s+(?<ColumnType>[^,]+),?";
|
||
var columnMatches = Regex.Matches(columnsDefinition, columnPattern);
|
||
|
||
foreach (Match match in columnMatches)
|
||
{
|
||
//var columnName = columnMatch.Groups["ColumnName"].Value;
|
||
//var columnType = columnMatch.Groups["ColumnType"].Value;
|
||
|
||
//columns.Add($"{columnName} {columnType}");
|
||
var columnInfo = new ColumnInfo
|
||
{
|
||
ColumnName = match.Groups["ColumnName"].Value,
|
||
DataType = match.Groups["DataType"].Value,
|
||
IsNullable = match.Groups["Nullability"].Value != "NOT NULL"
|
||
};
|
||
columns.Add(columnInfo);
|
||
|
||
//columns.Add(columnMatch.Groups["column"].Value);
|
||
}
|
||
|
||
return columns;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取当前数据库里的表结构
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public List<Table> GetDatabaseTableStructures()
|
||
{
|
||
var tableStructures = new List<Table>();
|
||
|
||
|
||
var tables = SqlSugarHelper.Db.Ado.GetDataTable($@"SELECT
|
||
*
|
||
FROM
|
||
information_schema.TABLES
|
||
WHERE
|
||
TABLE_SCHEMA = '{dbName}';");
|
||
|
||
foreach (System.Data.DataRow row in tables.Rows)
|
||
{
|
||
string tableName = row["TABLE_NAME"].ToString();
|
||
//var columns = new List<string>();
|
||
|
||
//using (var command = new MySqlCommand($"DESCRIBE {tableName}", connection))
|
||
//using (var reader = command.ExecuteReader())
|
||
//{
|
||
// while (reader.Read())
|
||
// {
|
||
// columns.Add(reader["Field"].ToString());
|
||
// }
|
||
//}
|
||
|
||
//tableStructures.Add(tableName, columns);
|
||
|
||
|
||
var TbColumns = new List<ColumnInfo>();
|
||
var columns = SqlSugarHelper.Db.Ado.GetDataTable($"DESCRIBE {tableName}");
|
||
foreach (System.Data.DataRow row2 in columns.Rows)
|
||
{
|
||
TbColumns.Add(new ColumnInfo()
|
||
{
|
||
ColumnName = row2["Field"].ToString(),
|
||
DataType = row2["Type"].ToString(),
|
||
IsNullable = row2["Null"].ToString() != "NO"
|
||
});
|
||
}
|
||
|
||
tableStructures.Add(new Table()
|
||
{
|
||
Name = tableName,
|
||
Columns = TbColumns
|
||
});
|
||
}
|
||
|
||
|
||
return tableStructures;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 比较sql抽取出来的表结构和当前数据库里的(增补sql小文件)
|
||
/// </summary>
|
||
/// <param name="sqlSchema"></param>
|
||
/// <param name="dbSchema"></param>
|
||
/// <returns></returns>
|
||
public List<string> CompareSchemas2(string sql, bool ProjectRelated,string SQLFILENAME)
|
||
{
|
||
var discrepancies = new List<string>();
|
||
#region 拓展出需要的各个项目的 从business table表?
|
||
var bsList = SqlSugarHelper.Db.Queryable<ec_business_tableEntity>().ToList();
|
||
var projList = SqlSugarHelper.Db.Queryable<ec_projectEntity>().ToList();
|
||
|
||
|
||
var subsql = sql.Split(';');
|
||
#region 处理
|
||
// 正则表达式
|
||
string pattern = @"(?<=ALTER\s+TABLE\s+`)[^`]+";
|
||
string pattern2 = @"(?<=CREATE\s+TABLE\s+`)[^`]+";
|
||
int patternType;//1是create,0是update
|
||
foreach (var sqlstr in subsql)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(sqlstr))
|
||
{
|
||
continue;
|
||
}
|
||
// 匹配表名
|
||
Match match = Regex.Match(sqlstr, pattern);
|
||
if (string.IsNullOrEmpty(sqlstr))
|
||
{
|
||
continue;
|
||
}
|
||
if (match.Length == 0)
|
||
{
|
||
match = Regex.Match(sqlstr, pattern2); patternType = 1;
|
||
}
|
||
else
|
||
{
|
||
patternType = 0;
|
||
}
|
||
if (match.Length == 0 )
|
||
{
|
||
//无效的sql
|
||
LogInfo(baseDirectory + logFileName, $"无法从{SQLFILENAME}.sql文件中解析出正确的create table 或 update table。确保是有效的sql。文本为 {sqlstr}");
|
||
continue;
|
||
}
|
||
var groupMatch = Regex.Matches(sqlstr, pattern);
|
||
#endregion
|
||
if (match.Success)
|
||
{
|
||
string tableName = match.Value;
|
||
Console.WriteLine("Table name: " + tableName);
|
||
//在Project文件夹下 或者 属于业务表
|
||
if (ProjectRelated || bsList.Select(x => x.BusinessTableCode.ToUpper()).Contains(tableName.ToUpper()))
|
||
{
|
||
//属于Project相关的表,需要重复执行
|
||
foreach (var proj in projList)
|
||
{
|
||
// 替换表名为其他表名
|
||
string newTableName = tableName + "_" + proj.ProjectIndex;
|
||
string modifiedSql = "";
|
||
if (patternType == 0)
|
||
{
|
||
modifiedSql = Regex.Replace(sqlstr, pattern, newTableName);
|
||
}
|
||
else
|
||
{
|
||
modifiedSql = Regex.Replace(sqlstr, pattern2, newTableName);
|
||
}
|
||
|
||
|
||
Console.WriteLine("Modified SQL: " + modifiedSql);
|
||
|
||
|
||
try
|
||
{
|
||
SqlSugarHelper.Db.Ado.ExecuteCommand(modifiedSql);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogInfo(baseDirectory + logFileName, tableName + " 项目表更新出现问题," + ex.Message);
|
||
}
|
||
}
|
||
}
|
||
|
||
//基础表,执行一次就行
|
||
try
|
||
{
|
||
SqlSugarHelper.Db.Ado.ExecuteCommand(sql);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogInfo(baseDirectory + logFileName, tableName + " 基础表更新出现问题," + ex.Message);
|
||
}
|
||
|
||
|
||
|
||
}
|
||
else
|
||
{
|
||
Console.WriteLine("Table name not found.");
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
|
||
return discrepancies;
|
||
}
|
||
/// <summary>
|
||
/// 比较sql抽取出来的表结构和当前数据库里的
|
||
/// </summary>
|
||
/// <param name="sqlSchema"></param>
|
||
/// <param name="dbSchema"></param>
|
||
/// <returns></returns>
|
||
public List<string> CompareSchemas(List<Table> sqlSchema, List<Table> dbSchema)
|
||
{
|
||
var discrepancies = new List<string>();
|
||
#region 拓展出需要的各个项目的 从business table表?
|
||
var bsList = SqlSugarHelper.Db.Queryable<ec_business_tableEntity>().ToList();
|
||
var projList = SqlSugarHelper.Db.Queryable<ec_projectEntity>().ToList();
|
||
|
||
//拓展sqlSchema里的记录,比如ec_enginedata,根据项目拓展到若干个
|
||
foreach (var bs in bsList)
|
||
{
|
||
var baseTb = sqlSchema.FirstOrDefault(x => x.Name.ToUpper() == bs.BusinessTableCode.ToUpper());
|
||
if (baseTb != null)
|
||
{
|
||
foreach (var proj in projList)
|
||
{
|
||
var projTb = new Table()
|
||
{
|
||
Name = baseTb.Name + "_" + proj.ProjectIndex,
|
||
Columns = baseTb.Columns
|
||
};
|
||
sqlSchema.Add(projTb);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//bus表里有问题
|
||
LogInfo(baseDirectory + logFileName, "ec_business_table表中的记录有问题 " + bs.BusinessTableID + " " + bs.BusinessTableCode);
|
||
}
|
||
}
|
||
#endregion
|
||
foreach (var table in sqlSchema)
|
||
{
|
||
if (!dbSchema.Any(x => x.Name.ToUpper() == table.Name.ToUpper()))
|
||
{
|
||
discrepancies.Add($"Table {table.Name} is missing in the database.");
|
||
continue;
|
||
}
|
||
|
||
var sqlColumns = table.Columns.Select(x => x.ColumnName.ToUpper()).ToList();
|
||
var dbColumns = dbSchema.FirstOrDefault(x => x.Name == table.Name).Columns.Select(x => x.ColumnName.ToUpper()).ToList();
|
||
|
||
// Find missing columns
|
||
foreach (var column in sqlColumns)
|
||
{
|
||
if (!dbColumns.Contains(column))
|
||
{
|
||
discrepancies.Add($"Column {column} is missing in table {table.Name}.");
|
||
}
|
||
}
|
||
}
|
||
|
||
return discrepancies;
|
||
}
|
||
/// <summary>
|
||
/// 根据比较结果,生成需要的SQL语句
|
||
/// </summary>
|
||
/// <param name="discrepancies"></param>
|
||
/// <param name="sqlSchema"></param>
|
||
/// <returns></returns>
|
||
public List<string> GenerateFixSql(List<string> discrepancies, List<Table> sqlSchema)
|
||
{
|
||
var sqlStatements = new List<string>();
|
||
|
||
foreach (var discrepancy in discrepancies)
|
||
{
|
||
var parts = discrepancy.Split(' ');
|
||
|
||
if (parts[0] == "Table")
|
||
{
|
||
// 生成创建表的SQL语句
|
||
string tableName = parts[1];
|
||
var columns = sqlSchema.FirstOrDefault(x => x.Name.ToUpper() == tableName.ToUpper())?.Columns;
|
||
string createTableSql = $"CREATE TABLE {tableName} (\n";
|
||
if (columns == null)
|
||
{
|
||
LogInfo(baseDirectory + logFileName, "GenerateFixSql时有问题 表匹配不到 " + tableName);
|
||
continue;
|
||
}
|
||
foreach (var column in columns)
|
||
{
|
||
if (column.IsNullable)
|
||
{
|
||
createTableSql += $"{column.ColumnName} {column.DataType} NULL ,\n"; // 简化的列定义,仅示例
|
||
}
|
||
else
|
||
{
|
||
createTableSql += $"{column.ColumnName} {column.DataType} NOT NULL ,\n"; // 简化的列定义,仅示例
|
||
}
|
||
}
|
||
|
||
createTableSql = createTableSql.TrimEnd(',', '\n') + "\n);";
|
||
sqlStatements.Add(createTableSql);
|
||
}
|
||
else if (parts[0] == "Column")
|
||
{
|
||
// 生成添加列的SQL语句
|
||
string columnName = parts[1];
|
||
string tableName = parts[6].Replace(".", "");
|
||
var columns = sqlSchema.FirstOrDefault(x => x.Name.ToUpper() == tableName.ToUpper())?.Columns;
|
||
|
||
if (columns == null)
|
||
{
|
||
LogInfo(baseDirectory + logFileName, "GenerateFixSql时有问题 表匹配不到 " + tableName);
|
||
continue;
|
||
}
|
||
|
||
var column = columns.FirstOrDefault(Y => Y.ColumnName.ToUpper() == columnName.ToUpper());
|
||
if (column == null)
|
||
{
|
||
LogInfo(baseDirectory + logFileName, "GenerateFixSql时有问题 列匹配不到 " + tableName + "." + columnName);
|
||
continue;
|
||
}
|
||
|
||
//sqlStatements.Add($"ALTER TABLE {tableName} ADD COLUMN {columnName} TEXT;");
|
||
if (column.IsNullable)
|
||
{
|
||
sqlStatements.Add($"ALTER TABLE {tableName} ADD COLUMN {columnName} {column.DataType} NULL;");
|
||
}
|
||
else
|
||
{
|
||
sqlStatements.Add($"ALTER TABLE {tableName} ADD COLUMN {columnName} {column.DataType} NOT NULL;");
|
||
}
|
||
}
|
||
}
|
||
|
||
return sqlStatements;
|
||
}
|
||
/// <summary>
|
||
/// 执行SQL
|
||
/// </summary>
|
||
/// <param name="SQLs"></param>
|
||
/// <returns></returns>
|
||
public async Task ExecuteComparisonSQL(List<string> SQLs)
|
||
{
|
||
foreach (var SQL in SQLs)
|
||
{
|
||
try
|
||
{
|
||
|
||
await UpdateText(SQL);
|
||
|
||
SqlSugarHelper.Db.Ado.ExecuteCommand(SQL);
|
||
|
||
}
|
||
catch (MySqlException ex)
|
||
{
|
||
LogError(baseDirectory + logFileName, ex, SQL);
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 打开日志
|
||
/// </summary>
|
||
/// <param name="sender"></param>
|
||
/// <param name="e"></param>
|
||
private void Button_Click_2(object sender, RoutedEventArgs e)
|
||
{
|
||
//打开log
|
||
|
||
try
|
||
{
|
||
ProcessStartInfo startInfo = new ProcessStartInfo()
|
||
{
|
||
FileName = "notepad.exe", // 指定使用记事本打开
|
||
Verb = "runas", // 使用管理员权限启动
|
||
Arguments = baseDirectory + logFileName,
|
||
UseShellExecute = true // 使用操作系统的Shell来执行
|
||
};
|
||
Process.Start(startInfo);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show("无法打开日志文件: " + ex.Message);
|
||
}
|
||
}
|
||
}
|
||
|
||
public class Table
|
||
{
|
||
public string Name { get; set; }
|
||
public List<ColumnInfo> Columns { get; set; }
|
||
}
|
||
|
||
public class ColumnInfo
|
||
{
|
||
public string ColumnName { get; set; }
|
||
public string DataType { get; set; }
|
||
public bool IsNullable { get; set; }
|
||
}
|
||
}
|
||
|
||
|
||
|