Form1.cs 16 KB

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