809 lines
30 KiB
C#
809 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);
|
|||
|
}
|
|||
|
|
|||
|
private void Button_Click(object sender, RoutedEventArgs e)
|
|||
|
{
|
|||
|
if (bInitialed)
|
|||
|
{
|
|||
|
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)
|
|||
|
{
|
|||
|
// 匹配表名
|
|||
|
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。");
|
|||
|
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; }
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|