Form1.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. using MySql.Data.MySqlClient;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Data;
  6. using System.Data.SQLite;
  7. using System.Drawing;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Threading.Tasks;
  12. using System.Windows.Forms;
  13. using System.Xml.Linq;
  14. using XdCxRhDW.Repostory;
  15. using Dapper;
  16. using XdCxRhDW.Entity;
  17. using XdCxRhDW.Framework;
  18. namespace DbMigrate
  19. {
  20. public partial class Form1 : Form
  21. {
  22. public Form1()
  23. {
  24. InitializeComponent();
  25. }
  26. private void btnSelectSqliteFile_Click(object sender, EventArgs e)
  27. {
  28. OpenFileDialog dialog = new OpenFileDialog();
  29. dialog.Filter = "|*.db";
  30. if (dialog.ShowDialog() != DialogResult.OK) return;
  31. txtSqliteFile.Text = dialog.FileName;
  32. }
  33. private async void txtSqliteFile_TextChanged(object sender, EventArgs e)
  34. {
  35. string file = txtSqliteFile.Text;
  36. if (!File.Exists(file)) return;
  37. try
  38. {
  39. checkedListBox1.Items.Clear();
  40. using (SQLiteConnection con = new SQLiteConnection($"Data Source={file}"))
  41. {
  42. await con.OpenAsync();
  43. var cmd = con.CreateCommand();
  44. cmd.CommandText = "select name from sqlite_master where type='table' and name not like 'sqlite%'";
  45. var reader = await cmd.ExecuteReaderAsync();
  46. while (await reader.ReadAsync())
  47. {
  48. var table = reader["name"].ToString();
  49. this.checkedListBox1.Items.Add(table);
  50. }
  51. for (int i = 0; i < checkedListBox1.Items.Count; i++)
  52. {
  53. checkedListBox1.SetItemChecked(i, true);
  54. }
  55. }
  56. }
  57. catch (Exception ex)
  58. {
  59. Log($"{file}不是有效的Sqlite库文件");
  60. }
  61. }
  62. private async void btnInitMySql_Click(object sender, EventArgs e)
  63. {
  64. try
  65. {
  66. this.groupBox1.Enabled = false;
  67. this.groupBox2.Enabled = false;
  68. this.panel2.Enabled = false;
  69. string conStr = txtMySqlCon.Text.Trim();
  70. if (!conStr.EndsWith(";"))
  71. conStr = $"{conStr};";
  72. //server=192.168.101.3;uid=root;pwd=123456;database=DWPT;
  73. var arr = conStr.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).Where(p => !p.ToLower().Contains("database")).ToList();
  74. var createDbCon = string.Join(";", arr) + ";";
  75. var conWithTimeout = $"{conStr}ConnectionTimeout=5;";
  76. string dbExistSql = "SELECT count(*) FROM information_schema.SCHEMATA where SCHEMA_NAME='dwpt'";
  77. string createDbSql = "CREATE DATABASE `dwpt` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */";
  78. if (!File.Exists("dwpt.sql")) return;
  79. using (MySqlConnection con = new MySqlConnection(createDbCon))
  80. {
  81. await con.OpenAsync();
  82. var count = await con.QueryFirstAsync<int>(dbExistSql);
  83. if (count == 0)
  84. await con.ExecuteAsync(createDbSql);
  85. }
  86. var commands = File.ReadAllText("dwpt.sql").Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList();
  87. commands.RemoveAll(p => p.All(q => q == '\n' || q == '\r' || q == '\t' || q == ' '));
  88. using (MySqlConnection db = new MySqlConnection(conWithTimeout))
  89. {
  90. foreach (string cmd in commands)
  91. {
  92. try
  93. {
  94. await db.ExecuteAsync(cmd);
  95. }
  96. catch (Exception ex)
  97. {
  98. LogHelper.Error("创建MySql数据库失败", ex);
  99. Log($"{ex.Message}");
  100. }
  101. }
  102. }
  103. Log("MySql数据库及表结构创建完成");
  104. }
  105. catch (Exception ex)
  106. {
  107. LogHelper.Error("创建MySql数据库及表结构失败", ex);
  108. Log($"创建MySql数据库及表结构失败.{ex.Message}");
  109. }
  110. finally
  111. {
  112. this.groupBox1.Enabled = true;
  113. this.groupBox2.Enabled = true;
  114. this.panel2.Enabled = true;
  115. }
  116. }
  117. private async void btnMigrate_Click(object sender, EventArgs e)
  118. {
  119. this.txtLog.Items.Clear();
  120. string file = txtSqliteFile.Text;
  121. if (!File.Exists(file))
  122. {
  123. Log($"Sqlite库文件{file}不存在!");
  124. return;
  125. }
  126. var tables = this.checkedListBox1.CheckedItems.Cast<string>().Select(p=>p.ToLower()).ToList();
  127. tables.Reverse();
  128. if (!tables.Any())
  129. {
  130. Log("请选择要迁移的表");
  131. return;
  132. }
  133. try
  134. {
  135. this.groupBox1.Enabled = false;
  136. this.groupBox2.Enabled = false;
  137. this.panel2.Enabled = false;
  138. File.WriteAllText("migrate.txt", $"{txtSqliteFile.Text}\r\n{txtMySqlCon.Text}");
  139. using (SQLiteConnection con = new SQLiteConnection($"Data Source={file}"))
  140. {
  141. try
  142. {
  143. await con.OpenAsync();
  144. }
  145. catch (Exception ex)
  146. {
  147. Log($"{file}不是有效的Sqlite库文件");
  148. return;
  149. }
  150. MySqlContext ctx = new MySqlContext(txtMySqlCon.Text);
  151. string database = ctx.Database.Connection.Database;
  152. var t = await ctx.ExecuteSqlCommandAsync("SET FOREIGN_KEY_CHECKS=0;");
  153. await ctx.SaveChangesAsync();
  154. foreach (var item in tables)
  155. {
  156. var type = GetEntityType(item);
  157. if (type == null)
  158. {
  159. Log($"跳过表{item}的数据迁移,不是系统需要的表!");
  160. continue;
  161. }
  162. var total = con.Query<long>($"select count(*) from {item}").First();
  163. Log($"正在迁移{item}表数据(共{total}条)...0%");
  164. long offset = 0;
  165. while (true)
  166. {
  167. var dataItems = await con.QueryAsync(type, $"select * from {item} order by id limit 1000 offset {offset}");
  168. if (item == "checkres")
  169. {
  170. foreach (CheckRes dataItem in dataItems)
  171. {
  172. dataItem.SigTime = await con.QueryFirstOrDefaultAsync<DateTime>($"select sigtime from posres where CheckResID={dataItem.ID}");
  173. }
  174. }
  175. if (item== "stationres")
  176. {
  177. foreach (StationRes dataItem in dataItems)
  178. {
  179. dataItem.SigTime = await con.QueryFirstOrDefaultAsync<DateTime>($"select sigtime from posres where StationResID={dataItem.ID}");
  180. }
  181. }
  182. if (dataItems.Any())
  183. {
  184. ctx.Set(type).AddRange(dataItems);
  185. await ctx.SaveChangesAsync();
  186. offset += dataItems.Count();
  187. UpdateProgress((int)(offset * 100 / total));
  188. }
  189. else
  190. {
  191. UpdateProgress(100);
  192. break;
  193. }
  194. }
  195. }
  196. t = await ctx.ExecuteSqlCommandAsync("SET FOREIGN_KEY_CHECKS=1;");
  197. await ctx.SaveChangesAsync();
  198. ctx.Dispose();
  199. Log($"数据迁移完成");
  200. }
  201. }
  202. catch (Exception ex)
  203. {
  204. LogHelper.Error("数据迁移失败", ex);
  205. Log($"数据迁移失败.{ex.Message}");
  206. }
  207. finally
  208. {
  209. this.groupBox1.Enabled = true;
  210. this.groupBox2.Enabled = true;
  211. this.panel2.Enabled = true;
  212. }
  213. }
  214. List<DateTime> GetRangeString(int year)
  215. {
  216. List<DateTime> list = new List<DateTime>();
  217. DateTime now = new DateTime(year, 1, 1, 0, 0, 0);
  218. while (true)
  219. {
  220. var d = Convert.ToInt32(now.DayOfWeek.ToString("d"));
  221. if (d == 0) d = 7;
  222. DateTime startWeek = now.AddDays(1 - d); //获取一周的开始日期
  223. list.Add(startWeek);
  224. now = now.AddDays(7);
  225. if (now.Year != year) break;
  226. }
  227. return list;
  228. }
  229. void Log(string msg)
  230. {
  231. txtLog.Items.Add($"{DateTime.Now:HH:mm:ss}--{msg}");
  232. }
  233. void UpdateProgress(int newValue)
  234. {
  235. int lastIdx = this.txtLog.Items.Count - 1;
  236. var last = this.txtLog.Items[lastIdx].ToString();
  237. last = last.Substring(0, last.IndexOf("..."));
  238. last = $"{last}...{newValue}%";
  239. this.txtLog.Items.RemoveAt(lastIdx);
  240. this.txtLog.Items.Add(last);
  241. }
  242. Type GetEntityType(string table)
  243. {
  244. if (table.ToLower() == nameof(XlInfo).ToLower()) return typeof(XlInfo);
  245. if (table.ToLower() == nameof(TaskInfo).ToLower()) return typeof(TaskInfo);
  246. if (table.ToLower() == nameof(TaskSig).ToLower()) return typeof(TaskSig);
  247. if (table.ToLower() == nameof(TxInfo).ToLower()) return typeof(TxInfo);
  248. if (table.ToLower() == nameof(SatInfo).ToLower()) return typeof(SatInfo);
  249. if (table.ToLower() == nameof(FixedStation).ToLower()) return typeof(FixedStation);
  250. if (table.ToLower() == nameof(SigInfo).ToLower()) return typeof(SigInfo);
  251. if (table.ToLower() == nameof(SigDelay).ToLower()) return typeof(SigDelay);
  252. if (table.ToLower() == nameof(TargetInfo).ToLower()) return typeof(TargetInfo);
  253. if (table.ToLower() == nameof(SysSetings).ToLower()) return typeof(SysSetings);
  254. if (table.ToLower() == nameof(TaskRunnningInfo).ToLower()) return typeof(TaskRunnningInfo);
  255. if (table.ToLower() == nameof(LogRes).ToLower()) return typeof(LogRes);
  256. if (table.ToLower() == nameof(StationRes).ToLower()) return typeof(StationRes);
  257. if (table.ToLower() == nameof(CxRes).ToLower()) return typeof(CxRes);
  258. if (table.ToLower() == nameof(CgRes).ToLower()) return typeof(CgRes);
  259. if (table.ToLower() == nameof(CgXgfRes).ToLower()) return typeof(CgXgfRes);
  260. if (table.ToLower() == nameof(PosRes).ToLower()) return typeof(PosRes);
  261. if (table.ToLower() == nameof(CheckRes).ToLower()) return typeof(CheckRes);
  262. return null;
  263. }
  264. private void Form1_Load(object sender, EventArgs e)
  265. {
  266. if (File.Exists("migrate.txt"))
  267. {
  268. try
  269. {
  270. var lines = File.ReadAllLines("migrate.txt");
  271. txtSqliteFile.Text = lines[0];
  272. txtMySqlCon.Text = lines[1];
  273. }
  274. catch { }
  275. }
  276. }
  277. private async void btnCreateRange_Click(object sender, EventArgs e)
  278. {
  279. if (MessageBox.Show("1.请按照年份从小到大创建分区\r\n2.比如系统一但创建了2025年的分区后无法再创建2024年的分区\r\n3.创建分区时最好不要有太多数据库读写操作", "是否继续?", MessageBoxButtons.YesNo) != DialogResult.Yes) return;
  280. this.groupBox1.Enabled = false;
  281. this.groupBox2.Enabled = false;
  282. this.panel2.Enabled = false;
  283. try
  284. {
  285. txtLog.Items.Clear();
  286. string conStr = txtMySqlCon.Text.Trim();
  287. if (!conStr.EndsWith(";"))
  288. conStr = $"{conStr};";
  289. List<string> tables = new List<string>() { "posres", "cgres", "cgxgfres", "cxres", "checkres", "stationres" };
  290. using (MySqlConnection con = new MySqlConnection(conStr))
  291. {
  292. await con.OpenAsync();
  293. foreach (var table in tables)
  294. {
  295. string sqlExist = $"SELECT count(*) FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA = 'dwpt' AND TABLE_NAME = '{table}' AND PARTITION_NAME = 'p_future'";
  296. var existed = (await con.QueryFirstAsync<int>(sqlExist)) > 0;
  297. if (!existed)
  298. {
  299. string sql = $"ALTER TABLE {table} " +
  300. "PARTITION BY RANGE (TO_DAYS(SigTime)) (" +
  301. $"PARTITION p_future VALUES LESS THAN MAXVALUE)";
  302. await con.ExecuteAsync(sql);
  303. }
  304. }
  305. }
  306. string str = txtYear.Text.Trim();
  307. if (str.Length != 4)
  308. {
  309. Log("年份输入错误!");
  310. return;
  311. }
  312. if (!int.TryParse(str, out int year))
  313. {
  314. Log("年份输入错误!");
  315. return;
  316. }
  317. var weekTimes = GetRangeString(year);
  318. using (MySqlConnection con = new MySqlConnection(conStr))
  319. {
  320. await con.OpenAsync();
  321. foreach (var table in tables)
  322. {
  323. foreach (var item in weekTimes)
  324. {
  325. var sqlExist = $"SELECT count(*) FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA = 'dwpt' AND TABLE_NAME = '{table}' AND PARTITION_NAME = 'p_{item:yyyyMMdd}'";
  326. var sql = $" ALTER TABLE {table} REORGANIZE PARTITION p_future into (PARTITION p_{item:yyyyMMdd} VALUES LESS THAN (TO_DAYS('{item.AddDays(7):yyyy-MM-dd HH:mm:ss}')),PARTITION p_future VALUES LESS THAN MAXVALUE )";
  327. var existed = (await con.QueryFirstAsync<int>(sqlExist)) > 0;
  328. if (!existed)
  329. {
  330. await con.ExecuteAsync(sql);
  331. Log($"表{table}分区p_{item:yyyyMMdd}创建完成");
  332. }
  333. else
  334. {
  335. Log($"表{table}分区p_{item:yyyyMMdd}创建跳过,已经存在此分区");
  336. }
  337. }
  338. }
  339. }
  340. Log($"分区创建完成");
  341. }
  342. catch (Exception ex)
  343. {
  344. LogHelper.Error("分区创建异常", ex);
  345. Log($"分区创建异常.{ex.Message}");
  346. }
  347. finally
  348. {
  349. this.groupBox1.Enabled = true;
  350. this.groupBox2.Enabled = true;
  351. this.panel2.Enabled = true;
  352. }
  353. /*
  354. *
  355. */
  356. }
  357. }
  358. }