From f6c1f28693a417a956d36abc2f7670d34539864f Mon Sep 17 00:00:00 2001 From: "jay.chang" Date: Fri, 28 Mar 2025 17:13:18 +0800 Subject: [PATCH] =?UTF-8?q?[Backend]=E5=9B=A0=E6=87=89=E5=B7=A8=E8=9B=8B?= =?UTF-8?q?=E6=A3=9F=E5=90=8C=E6=AD=A5=E5=A4=B1=E6=95=97=EF=BC=8C=E5=84=AA?= =?UTF-8?q?=E5=8C=96=E5=90=8C=E6=AD=A5=E7=A8=8B=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NiagaraDataSynchronizeRepository.cs | 674 +++++++++--------- 1 file changed, 350 insertions(+), 324 deletions(-) diff --git a/Repository/BackendRepository/Implement/NiagaraDataSynchronizeRepository.cs b/Repository/BackendRepository/Implement/NiagaraDataSynchronizeRepository.cs index cabd432..1e13bef 100644 --- a/Repository/BackendRepository/Implement/NiagaraDataSynchronizeRepository.cs +++ b/Repository/BackendRepository/Implement/NiagaraDataSynchronizeRepository.cs @@ -90,11 +90,11 @@ namespace Repository.BackendRepository.Implement { tag_name = x.Key.tag_name2, displayName = x.Key.displayName2 - }); - + }); + // StringBuilder sb = new StringBuilder(); bool isDome = false; //是否為巨蛋案 - int count = 0; + int count = 0; stopwatchSection = new Stopwatch(); stopwatchSection.Start(); foreach (var row in ds2) @@ -125,7 +125,7 @@ namespace Repository.BackendRepository.Implement { if (arrTag.Length == 5) { - isDome= true; + isDome = true; sb.Append($@" insert into import_niagara_tag(niagara_tags, device_area_tag, device_building_tag, device_system_tag, device_name_tag, device_floor_tag, device_master_tag, device_last_name_tag, device_serial_tag, device_model_tag, device_full_name, atDateTime) values('" + row.tag_name + "', '" + //niagara_tags @@ -209,7 +209,7 @@ namespace Repository.BackendRepository.Implement } } } - + /// /// 獲取照明開關 是否在 device_node 層 /// @@ -220,9 +220,9 @@ namespace Repository.BackendRepository.Implement stopwatch.Start(); using (IDbConnection conn = GetDbConnection()) { - conn.Open(); + conn.Open(); var sql = "select system_value from variable where system_type = 'module_light_switch' "; - var module_light_switch = conn.QueryAsync(sql).Result.FirstOrDefault(); + var module_light_switch = conn.QueryAsync(sql).Result.FirstOrDefault(); conn.Close(); stopwatch.Stop(); await KeepTimeLog("getLightSwitchLevel", stopwatch.ElapsedMilliseconds); @@ -250,7 +250,7 @@ namespace Repository.BackendRepository.Implement { stopwatchSection = new Stopwatch(); stopwatchSection.Start(); - foreach(var b in building) + foreach (var b in building) { string sql = @"CREATE TABLE IF NOT EXISTS `import_niagara_item` ( `id` int(11) NOT NULL AUTO_INCREMENT, @@ -281,7 +281,8 @@ namespace Repository.BackendRepository.Implement stopwatchSection = new Stopwatch(); stopwatchSection.Start(); - ds = ds.GroupBy(x => new { + ds = ds.GroupBy(x => new + { device_area_tag = x.device_area_tag, device_building_tag = x.device_building_tag, device_system_tag = x.device_system_tag, @@ -304,7 +305,7 @@ namespace Repository.BackendRepository.Implement foreach (var row in ds) { sb.Append($@" insert import_niagara_item(device_area_tag, device_building_tag, device_system_tag, device_name_tag, device_point_name, parent_path, full_name, is_history) - values('"+ + values('" + row.device_area_tag + "', '" + row.device_building_tag + "', '" + row.device_system_tag + "', '" + @@ -446,7 +447,7 @@ namespace Repository.BackendRepository.Implement { conn.Close(); } - + } } @@ -456,376 +457,404 @@ namespace Repository.BackendRepository.Implement /// public async Task DeviceComparison(string LightSwitchLevel) { - stopwatch = new Stopwatch(); - stopwatch.Start(); + Stopwatch stopwatch = Stopwatch.StartNew(); + using (IDbConnection conn = GetDbConnection()) { conn.Open(); + try { - List result; - StringBuilder sb = new StringBuilder(); - StringBuilder sb2 = new StringBuilder(); - stopwatchSection = new Stopwatch(); - stopwatchSection.Start(); - sb.Append($@"SELECT m.* - FROM import_niagara_tag m - WHERE NOT EXISTS ( - SELECT 1 - FROM device d - WHERE m.niagara_tags = d.device_number - );"); - result = (await conn.QueryAsync(sb.ToString())).ToList(); - sb.Clear(); - stopwatchSection.Stop(); - await KeepTimeLog("filter device item from import_niagara_tag", stopwatchSection.ElapsedMilliseconds); + // 1. 取得需要新增的 NiagaraTags + Stopwatch sw1 = Stopwatch.StartNew(); + string sqlGetNiagaraTags = @" + SELECT m.* + FROM import_niagara_tag m + WHERE NOT EXISTS ( + SELECT 1 + FROM device d + WHERE m.niagara_tags = d.device_number + );"; + List niagaraTagsToAdd = (await conn.QueryAsync(sqlGetNiagaraTags)).ToList(); + sw1.Stop(); + await KeepTimeLog("filter device item from import_niagara_tag", sw1.ElapsedMilliseconds); - #region device, device_kind 新增 - stopwatchSection = new Stopwatch(); - stopwatchSection.Start(); - int count = 0; - //新增至device, is_link = 1 - if (result.Count > 0) + // 2. 新增 device 和 device_kind + if (niagaraTagsToAdd.Count > 0) { - var result2 = result.GroupBy(x => new + // 2.1. 新增 device + Stopwatch sw2 = Stopwatch.StartNew(); + List sqlInsertDeviceList = new List(); + foreach (var data in niagaraTagsToAdd) { - device_building_tag2 = x.device_building_tag, - device_system_tag2 = x.device_system_tag, - device_name_tag2 = x.device_name_tag - }).Select(x => new Device_item8 - { - device_building_tag = x.Key.device_building_tag2, - device_system_tag = x.Key.device_system_tag2, - device_name_tag = x.Key.device_name_tag2 - }); - - foreach (var data in result) - { - //開關控制在個別燈具(device_node層) and 小類為二線式照明系統 and tag第八段開頭不是 G if (LightSwitchLevel == "node" && data.device_name_tag == "L1" && data.device_serial_tag.Substring(0, 1) != "G") { // 燈具新增 device_node continue; } - else { - sb.Append($@" insert device(device_guid, deleted, status, priority, is_link, device_area_tag, - device_building_tag, device_system_tag, device_name_tag, full_name, device_floor_tag, device_master, - device_last_name, device_serial_tag, device_model_tag, device_number, device_system_category_layer3, visible, created_at, updated_at) - values(uuid(), 0, 1, 0, 1, '" + - data.device_area_tag + "', '" + - data.device_building_tag + "', '" + - data.device_system_tag + "', '" + - data.device_name_tag + "', '" + - data.device_full_name + "', '" + - data.device_floor_tag + "', '" + - data.device_master_tag + "', '" + - data.device_last_name_tag + "', '" + - data.device_serial_tag + "', '" + - data.device_model_tag + "', '" + - data.niagara_tags + "', '" + - data.device_system_tag + "', 1, now(), now() );"); - count += 1; - if (count >= 100) - { - using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) - { - await conn.ExecuteAsync(sb.ToString()); - } - sb.Clear(); - count = 0; - } - } + + string sqlInsertDevice = @" + INSERT INTO device (device_guid, deleted, status, priority, is_link, device_area_tag, + device_building_tag, device_system_tag, device_name_tag, full_name, device_floor_tag, device_master, + device_last_name, device_serial_tag, device_model_tag, device_number, device_system_category_layer3, visible, created_at, updated_at) + VALUES (uuid(), 0, 1, 0, 1, @device_area_tag, @device_building_tag, @device_system_tag, @device_name_tag, + @full_name, @device_floor_tag, @device_master_tag, @device_last_name_tag, @device_serial_tag, + @device_model_tag, @niagara_tags, @device_system_tag, 1, now(), now());"; + + sqlInsertDeviceList.Add(sqlInsertDevice); // 先暫存SQL語法,等等一次執行 } - if (sb.Length > 0) + // 2.1.1 分批執行新增 device + int batchSize = 100; + for (int i = 0; i < sqlInsertDeviceList.Count; i += batchSize) { + //建立參數 + var batch = niagaraTagsToAdd.Skip(i).Take(batchSize).ToList(); + //建立參數化查詢要用的物件 + List parameters = new List(); + foreach (var data in batch) + { + parameters.Add(new + { + device_area_tag = data.device_area_tag, + device_building_tag = data.device_building_tag, + device_system_tag = data.device_system_tag, + device_name_tag = data.device_name_tag, + full_name = data.device_full_name, + device_floor_tag = data.device_floor_tag, + device_master_tag = data.device_master_tag, + device_last_name_tag = data.device_last_name_tag, + device_serial_tag = data.device_serial_tag, + device_model_tag = data.device_model_tag, + niagara_tags = data.niagara_tags + }); + } + //建立多條Insert語法,可以搭配Dapper的參數化查詢 + string insertSql = string.Join(" ", sqlInsertDeviceList.Take(batchSize)); + using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) { - await conn.ExecuteAsync(sb.ToString()); - } - - sb.Clear(); - } - stopwatchSection.Stop(); - await KeepTimeLog("insert into device", stopwatchSection.ElapsedMilliseconds); - - stopwatchSection = new Stopwatch(); - stopwatchSection.Start(); - foreach (var data in result2) - { - var sqlString = new StringBuilder(); - sqlString.Append("select * from device_kind where device_building_tag = '" + data.device_building_tag + "' and device_system_tag = '" + data.device_system_tag + "' and device_name_tag = '" + data.device_name_tag + "'"); - var dk = (await conn.QueryAsync(sqlString.ToString())).ToList(); - - if (dk.Count == 0) - { - sb2.Append($@"INSERT device_kind (device_kind_guid, device_building_tag, device_system_tag, device_name_tag, - device_normal_flashing, device_close_flashing, device_error_flashing, device_error_independent, - created_by, created_at, is_link) - VALUES (uuid(), '" + data.device_building_tag + "', '" + data.device_system_tag + "', '" + data.device_name_tag + - "', 0, 0, 1, 0, 'B43E3CA7-96DD-4FC7-B6E6-974ACC3B0878', now(), 1);"); - count += 1; - if (count >= 100) - { - using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) - { - await conn.ExecuteAsync(sb2.ToString()); - } - sb2.Clear(); - count = 0; - } + await conn.ExecuteAsync(insertSql, parameters); // 使用參數化查詢 + scope.Complete(); } } - if (sb2.Length > 0) + sw2.Stop(); + await KeepTimeLog("insert into device", sw2.ElapsedMilliseconds); + + // 2.2. 新增 device_kind + Stopwatch sw3 = Stopwatch.StartNew(); + + // 建立 device_kind 時需要用到的資料結構 + var deviceKindData = niagaraTagsToAdd.GroupBy(x => new { - using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) - { - await conn.ExecuteAsync(sb2.ToString()); - } - - sb2.Clear(); - } - stopwatchSection.Stop(); - await KeepTimeLog("insert into device_kind", stopwatchSection.ElapsedMilliseconds); - } - #endregion - - #region device_kind process for cctv - stopwatchSection = new Stopwatch(); - stopwatchSection.Start(); - using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) - { - await conn.ExecuteAsync(@"SET SQL_SAFE_UPDATES = 0; - update device d join import_niagara_tag n on d.device_number = n.niagara_tags set d.device_model_tag = n.device_model_tag - where d.device_system_tag = 'S' and d.device_name_tag = 'C' and (d.device_model_tag is null or d.device_model_tag = '');"); - } - stopwatchSection.Stop(); - await KeepTimeLog("update cctv model is null or empty", stopwatchSection.ElapsedMilliseconds); - - stopwatchSection = new Stopwatch(); - stopwatchSection.Start(); - var resultDeviceItem = await conn.QueryAsync($@"select * from import_niagara_tag where device_system_tag = 'S' and device_name_tag = 'C';"); - var result3 = resultDeviceItem.GroupBy(x => new - { - device_building_tag2 = x.device_building_tag, - device_system_tag2 = x.device_system_tag, - device_name_tag2 = x.device_name_tag, - device_model_tag2 = x.device_model_tag - }).Select(x => new Device_item8 - { - device_building_tag = x.Key.device_building_tag2, - device_system_tag = x.Key.device_system_tag2, - device_name_tag = x.Key.device_name_tag2, - device_model_tag = x.Key.device_model_tag2 - }); - - foreach (var data in result3) - { - var sqlString = new StringBuilder(); - sqlString.Append("select * from device_kind where device_building_tag = '" + data.device_building_tag + "' and device_system_tag = '" + data.device_system_tag + "' and device_name_tag = '" + data.device_name_tag + "' and device_model_tag = '" + data.device_model_tag + "'"); - var dk = (await conn.QueryAsync(sqlString.ToString())).ToList(); - - if (dk.Count == 0) + x.device_building_tag, + x.device_system_tag, + x.device_name_tag + }).Select(g => new { - sb2.Append($@"INSERT device_kind (device_kind_guid, device_building_tag, device_system_tag, device_name_tag, - device_normal_flashing, device_close_flashing, device_error_flashing, device_error_independent, - created_by, created_at, device_model_tag, is_link) - VALUES (uuid(), '" + data.device_building_tag + "', '" + data.device_system_tag + "', '" + data.device_name_tag + - "', 0, 0, 1, 0, 'B43E3CA7-96DD-4FC7-B6E6-974ACC3B0878', now(), '" + data.device_model_tag + "', 1);"); - count += 1; - if (count >= 100) + g.Key.device_building_tag, + g.Key.device_system_tag, + g.Key.device_name_tag + }).ToList(); + + foreach (var data in deviceKindData) + { + // 檢查 device_kind 是否已存在 (改成使用 EXISTS 子查詢) + string sqlCheckDeviceKind = @" + SELECT EXISTS ( + SELECT 1 + FROM device_kind + WHERE device_building_tag = @device_building_tag + AND device_system_tag = @device_system_tag + AND device_name_tag = @device_name_tag + );"; + var parameters = new { device_building_tag = data.device_building_tag, device_system_tag = data.device_system_tag, device_name_tag = data.device_name_tag }; + bool deviceKindExists = await conn.ExecuteScalarAsync(sqlCheckDeviceKind, parameters); // 使用參數化查詢 + + if (!deviceKindExists) { + // 新增 device_kind + string sqlInsertDeviceKind = @" + INSERT INTO device_kind (device_kind_guid, device_building_tag, device_system_tag, device_name_tag, + device_normal_flashing, device_close_flashing, device_error_flashing, device_error_independent, + created_by, created_at, is_link) + VALUES (uuid(), @device_building_tag, @device_system_tag, @device_name_tag, + 0, 0, 1, 0, 'B43E3CA7-96DD-4FC7-B6E6-974ACC3B0878', now(), 1);"; + + var parameters2 = new { device_building_tag = data.device_building_tag, device_system_tag = data.device_system_tag, device_name_tag = data.device_name_tag }; using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) { - await conn.ExecuteAsync(sb2.ToString()); + await conn.ExecuteAsync(sqlInsertDeviceKind, parameters2); // 使用參數化查詢 + scope.Complete(); } - sb2.Clear(); - count = 0; + } + } + + sw3.Stop(); + await KeepTimeLog("insert into device_kind", sw3.ElapsedMilliseconds); + } + + // 3. device_kind process for cctv + Stopwatch sw4 = Stopwatch.StartNew(); + + // 3.1 更新 device 的 model tag + string sqlUpdateCCTVModel = @" + UPDATE device d + JOIN import_niagara_tag n ON d.device_number = n.niagara_tags + SET d.device_model_tag = n.device_model_tag + WHERE d.device_system_tag = 'S' + AND d.device_name_tag = 'C' + AND (d.device_model_tag IS NULL OR d.device_model_tag = '');"; + + using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) + { + await conn.ExecuteAsync(sqlUpdateCCTVModel); // 使用參數化查詢 + scope.Complete(); + } + + sw4.Stop(); + await KeepTimeLog("update cctv model is null or empty", sw4.ElapsedMilliseconds); + + // 3.2 取得 CCTV 相關資料,並新增 device_kind (邏輯同 2.2,但需要額外考量 device_model_tag) + Stopwatch sw5 = Stopwatch.StartNew(); + + string sqlGetCCTVData = @"SELECT * FROM import_niagara_tag WHERE device_system_tag = 'S' AND device_name_tag = 'C';"; + var cctvData = await conn.QueryAsync(sqlGetCCTVData); + + // 建立 device_kind 時需要用到的資料結構 + var cctvKindData = cctvData.GroupBy(x => new + { + x.device_building_tag, + x.device_system_tag, + x.device_name_tag, + x.device_model_tag + }).Select(g => new + { + g.Key.device_building_tag, + g.Key.device_system_tag, + g.Key.device_name_tag, + g.Key.device_model_tag + }).ToList(); + + foreach (var data in cctvKindData) + { + // 檢查 device_kind 是否已存在 (改成使用 EXISTS 子查詢) + string sqlCheckDeviceKind = @" + SELECT EXISTS ( + SELECT 1 + FROM device_kind + WHERE device_building_tag = @device_building_tag + AND device_system_tag = @device_system_tag + AND device_name_tag = @device_name_tag + AND device_model_tag = @device_model_tag + );"; + + var parameters = new { device_building_tag = data.device_building_tag, device_system_tag = data.device_system_tag, device_name_tag = data.device_name_tag, device_model_tag = data.device_model_tag }; + bool deviceKindExists = await conn.ExecuteScalarAsync(sqlCheckDeviceKind, parameters); + + if (!deviceKindExists) + { + // 新增 device_kind + string sqlInsertDeviceKind = @" + INSERT INTO device_kind (device_kind_guid, device_building_tag, device_system_tag, device_name_tag, + device_normal_flashing, device_close_flashing, device_error_flashing, device_error_independent, + created_by, created_at, device_model_tag, is_link) + VALUES (uuid(), @device_building_tag, @device_system_tag, @device_name_tag, + 0, 0, 1, 0, 'B43E3CA7-96DD-4FC7-B6E6-974ACC3B0878', now(), @device_model_tag, 1);"; + + var parameters2 = new { device_building_tag = data.device_building_tag, device_system_tag = data.device_system_tag, device_name_tag = data.device_name_tag, device_model_tag = data.device_model_tag }; + using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) + { + await conn.ExecuteAsync(sqlInsertDeviceKind, parameters2); // 使用參數化查詢 + scope.Complete(); } } } - if (sb2.Length > 0) - { - using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) - { - await conn.ExecuteAsync(sb2.ToString()); - } + sw5.Stop(); + await KeepTimeLog("insert cctv device_kind", sw5.ElapsedMilliseconds); - sb2.Clear(); - } + // 3.3 更新 device_kind 的 is_link (邏輯複雜,需要仔細確認SQL語法) + Stopwatch sw6 = Stopwatch.StartNew(); + + // 先更新 device_kind 的 is_link 為 0 + string sqlUpdateDeviceKindIsLinkToZero = @" + UPDATE device_kind + SET is_link = 0 + WHERE device_system_tag = 'S' + AND device_name_tag = 'C' + AND NOT EXISTS ( + SELECT 1 + FROM import_niagara_tag + WHERE device_system_tag = device_kind.device_system_tag + AND device_name_tag = device_kind.device_name_tag + AND device_model_tag = device_kind.device_model_tag + );"; using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) { - await conn.ExecuteAsync($@"SET SQL_SAFE_UPDATES = 0; - UPDATE device_kind dk - left JOIN ( - SELECT device_system_tag, device_name_tag, device_model_tag - FROM import_niagara_tag - LIMIT 100000 - ) i ON dk.device_system_tag = i.device_system_tag - and dk.device_name_tag = i.device_name_tag - and dk.device_model_tag = i.device_model_tag - SET dk.is_link = 0 - WHERE dk.is_link = 1 and dk.device_system_tag = 'S' and dk.device_name_tag = 'C' and i.device_system_tag is null;"); + await conn.ExecuteAsync(sqlUpdateDeviceKindIsLinkToZero); // 使用參數化查詢 + scope.Complete(); } + // 再更新 device_kind 的 is_link 為 1 + string sqlUpdateDeviceKindIsLinkToOne = @" + UPDATE device_kind + SET is_link = 1 + WHERE device_system_tag = 'S' + AND device_name_tag = 'C' + AND EXISTS ( + SELECT 1 + FROM import_niagara_tag + WHERE device_system_tag = device_kind.device_system_tag + AND device_name_tag = device_kind.device_name_tag + AND device_model_tag = device_kind.device_model_tag + );"; + using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) { - await conn.ExecuteAsync($@"SET SQL_SAFE_UPDATES = 0; - UPDATE device_kind dk - left JOIN ( - SELECT device_system_tag, device_name_tag, device_model_tag - FROM import_niagara_tag - LIMIT 100000 - ) i ON dk.device_system_tag = i.device_system_tag - and dk.device_name_tag = i.device_name_tag - and dk.device_model_tag = i.device_model_tag - SET dk.is_link = 1 - WHERE dk.is_link = 0 and dk.device_system_tag = 'S' and dk.device_name_tag = 'C' and i.device_system_tag is not null;"); + await conn.ExecuteAsync(sqlUpdateDeviceKindIsLinkToOne); // 使用參數化查詢 + scope.Complete(); } - stopwatchSection.Stop(); - await KeepTimeLog("insert/update cctv model is_link", stopwatchSection.ElapsedMilliseconds); - #endregion - #region device_node 新增 - stopwatchSection = new Stopwatch(); - stopwatchSection.Start(); - sb.Append($@" SELECT m.* - FROM import_niagara_tag m - WHERE NOT EXISTS ( - SELECT 1 - FROM device_node d - WHERE m.niagara_tags COLLATE utf8mb4_0900_ai_ci = d.device_number COLLATE utf8mb4_0900_ai_ci - );"); - result = (await conn.QueryAsync(sb.ToString())).ToList(); - sb.Clear(); + sw6.Stop(); + await KeepTimeLog("insert/update cctv model is_link", sw6.ElapsedMilliseconds); - if (result.Count > 0) + // 4. device_node 新增 (邏輯同 2.1,需要調整 SQL 語法和參數) + Stopwatch sw7 = Stopwatch.StartNew(); + string sqlGetNiagaraTagsForNode = @" + SELECT m.* + FROM import_niagara_tag m + WHERE NOT EXISTS ( + SELECT 1 + FROM device_node d + WHERE m.niagara_tags = d.device_number + );"; + List niagaraTagsToAddForNode = (await conn.QueryAsync(sqlGetNiagaraTagsForNode)).ToList(); + + if (niagaraTagsToAddForNode.Count > 0) { - var result2 = result.GroupBy(x => new + // 4.1. 新增 device_node + List sqlInsertDeviceNodeList = new List(); + foreach (var data in niagaraTagsToAddForNode) { - device_building_tag2 = x.device_building_tag, - device_system_tag2 = x.device_system_tag, - device_name_tag2 = x.device_name_tag - }).Select(x => new Device_item8 - { - device_building_tag = x.Key.device_building_tag2, - device_system_tag = x.Key.device_system_tag2, - device_name_tag = x.Key.device_name_tag2 - }); - - count = 0; - foreach (var data in result) - { - //開關控制在個別燈具(device_node層) and 小類為二線式照明系統 and tag第八段開頭不是 G if (LightSwitchLevel == "node" && data.device_name_tag == "L1" && data.device_serial_tag.Substring(0, 1) != "G") { // 燈具新增 device_node - sb.Append($@"INSERT INTO device_node(device_node_guid, deleted, device_guid, device_number, full_name, created_by, created_at, updated_at) - VALUES (uuid(), 0, '' " + //device_guid 父層需要 forge 那邊提供 - ",'" + data.niagara_tags + // device_number - "', '" + data.device_full_name + //full_name - "','B43E3CA7-96DD-4FC7-B6E6-974ACC3B0878', now(), now());"); - count += 1; - if (count >= 100) - { - using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) - { - await conn.ExecuteAsync(sb.ToString()); - } - sb.Clear(); - count = 0; - } + string sqlInsertDeviceNode = @" + INSERT INTO device_node (device_node_guid, deleted, device_guid, device_number, full_name, created_by, created_at, updated_at) + VALUES (uuid(), 0, '', @device_number, @full_name, 'B43E3CA7-96DD-4FC7-B6E6-974ACC3B0878', now(), now());"; + sqlInsertDeviceNodeList.Add(sqlInsertDeviceNode); } } - - if (sb.Length > 0) + //4.1.1 分批執行新增device node + int batchSizeNode = 100; + for (int i = 0; i < sqlInsertDeviceNodeList.Count; i += batchSizeNode) { + //建立參數 + var batch = niagaraTagsToAddForNode.Skip(i).Take(batchSizeNode).ToList(); + //建立參數化查詢要用的物件 + List parameters = new List(); + foreach (var data in batch) + { + parameters.Add(new + { + device_number = data.niagara_tags, + full_name = data.device_full_name, + }); + } + //建立多條Insert語法,可以搭配Dapper的參數化查詢 + string insertSql = string.Join(" ", sqlInsertDeviceNodeList.Take(batchSizeNode)); + using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) { - await conn.ExecuteAsync(sb.ToString()); + await conn.ExecuteAsync(insertSql, parameters); // 使用參數化查詢 + scope.Complete(); } - sb.Clear(); } - stopwatchSection.Stop(); - await KeepTimeLog("insert into device_node", stopwatchSection.ElapsedMilliseconds); } - #endregion + sw7.Stop(); + await KeepTimeLog("insert into device_node", sw7.ElapsedMilliseconds); - stopwatchSection = new Stopwatch(); - stopwatchSection.Start(); - //device有,niagara有,is_link 更新成 1 - sb.Append($@" SET SQL_SAFE_UPDATES = 0; - UPDATE device d - JOIN ( - SELECT niagara_tags - FROM import_niagara_tag - LIMIT 100000 - ) i ON d.device_number = i.niagara_tags - SET d.is_link = 1, d.deleted = 0"); - using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) - { - await conn.ExecuteAsync(sb.ToString()); - } - sb.Clear(); - stopwatchSection.Stop(); - await KeepTimeLog("update device is_link = 1, deleted = 0", stopwatchSection.ElapsedMilliseconds); - stopwatchSection = new Stopwatch(); - stopwatchSection.Start(); - //device有,niagara沒有,is_link 更新成 0 - sb.Append($@" SET SQL_SAFE_UPDATES = 0; - UPDATE device d - left JOIN ( - SELECT niagara_tags - FROM import_niagara_tag - LIMIT 100000 - ) i ON d.device_number = i.niagara_tags - SET d.is_link = 0 - WHERE d.is_link = 1 and i.niagara_tags is null;"); - using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) - { - await conn.ExecuteAsync(sb.ToString()); - } - sb.Clear(); - stopwatchSection.Stop(); - await KeepTimeLog("update device is_link = 0", stopwatchSection.ElapsedMilliseconds); + // 5. 更新 device 的 is_link + Stopwatch sw8 = Stopwatch.StartNew(); - stopwatchSection = new Stopwatch(); - stopwatchSection.Start(); - // device_node 有, niagara沒有, is_link 更新成 0 - sb.Append($@" SET SQL_SAFE_UPDATES = 0; - UPDATE device_node dn - left JOIN ( - SELECT niagara_tags - FROM import_niagara_tag - LIMIT 100000 - ) i ON dn.device_number COLLATE utf8mb4_0900_ai_ci = i.niagara_tags COLLATE utf8mb4_0900_ai_ci - SET dn.is_link = 0 - WHERE dn.is_link = 1 and i.niagara_tags is null;"); + // 先更新 device 的 is_link 為 1 (邏輯簡單,直接使用 UPDATE JOIN) + string sqlUpdateDeviceIsLinkToOne = @" + UPDATE device d + JOIN import_niagara_tag i ON d.device_number = i.niagara_tags + SET d.is_link = 1, d.deleted = 0;"; using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) { - await conn.ExecuteAsync(sb.ToString()); + await conn.ExecuteAsync(sqlUpdateDeviceIsLinkToOne); // 使用參數化查詢 + scope.Complete(); } - stopwatchSection.Stop(); - await KeepTimeLog("update device_node is_link = 0", stopwatchSection.ElapsedMilliseconds); + sw8.Stop(); + await KeepTimeLog("update device is_link = 1, deleted = 0", sw8.ElapsedMilliseconds); + + // 再更新 device 的 is_link 為 0 (邏輯需要調整,使用 NOT EXISTS 子查詢) + Stopwatch sw9 = Stopwatch.StartNew(); + + string sqlUpdateDeviceIsLinkToZero = @" + UPDATE device + SET is_link = 0 + WHERE is_link = 1 + AND NOT EXISTS ( + SELECT 1 + FROM import_niagara_tag + WHERE device.device_number = import_niagara_tag.niagara_tags + );"; + + using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) + { + await conn.ExecuteAsync(sqlUpdateDeviceIsLinkToZero); // 使用參數化查詢 + scope.Complete(); + } + + sw9.Stop(); + await KeepTimeLog("update device is_link = 0", sw9.ElapsedMilliseconds); + + // 6. 更新 device_node 的 is_link (邏輯同 5,需要調整 SQL 語法和參數) + Stopwatch sw10 = Stopwatch.StartNew(); + + string sqlUpdateDeviceNodeIsLinkToZero = @" + UPDATE device_node + SET is_link = 0 + WHERE is_link = 1 + AND NOT EXISTS ( + SELECT 1 + FROM import_niagara_tag + WHERE device_node.device_number = import_niagara_tag.niagara_tags + );"; + + using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) + { + await conn.ExecuteAsync(sqlUpdateDeviceNodeIsLinkToZero); // 使用參數化查詢 + scope.Complete(); + } + + sw10.Stop(); + await KeepTimeLog("update device_node is_link = 0", sw10.ElapsedMilliseconds); + + //Main總時間 stopwatch.Stop(); await KeepTimeLog("DeviceComparison", stopwatch.ElapsedMilliseconds); } catch (Exception exception) { - //throw exception; - throw; + throw; // 保留原始堆疊追蹤 } finally { - conn.Close(); + if (conn.State == ConnectionState.Open) + { + conn.Close(); + } } - } } @@ -1335,7 +1364,7 @@ namespace Repository.BackendRepository.Implement throw exception; } finally - { + { conn.Close(); } } @@ -1356,7 +1385,8 @@ namespace Repository.BackendRepository.Implement try { StringBuilder sb = new StringBuilder(); - sb.Append("update device set full_name=device_number where full_Name='';"); + sb.Append(@"SET SQL_SAFE_UPDATES = 0; + update device set full_name=device_number where full_Name='';"); await conn.ExecuteAsync(sb.ToString()); } catch (Exception exception) @@ -1424,17 +1454,13 @@ namespace Repository.BackendRepository.Implement { StringBuilder sb = new StringBuilder(); sb.Append(@"SET SQL_SAFE_UPDATES = 0; - update device d - JOIN ( - select niagara_tags, device_full_name from import_niagara_tag limit 100000 - ) m ON m.niagara_tags = d.device_number - LEFT JOIN ( - SELECT niagara_tags, device_full_name - FROM import_niagara_tag - LIMIT 100000 - ) m2 ON m2.niagara_tags = d.device_number AND m2.device_full_name = d.full_name - SET d.full_name = m.device_full_name - WHERE m2.niagara_tags IS NULL;"); + + UPDATE device AS d + JOIN import_niagara_tag AS i ON d.device_number = i.niagara_tags + SET d.full_name = i.device_full_name + WHERE d.full_name <> i.device_full_name; + + SET SQL_SAFE_UPDATES = 1;"); await conn.ExecuteAsync(sb.ToString()); } catch (Exception exception) @@ -1591,7 +1617,7 @@ namespace Repository.BackendRepository.Implement conn.Close(); } } - + stopwatchSection = new Stopwatch(); stopwatchSection.Start(); // 過濾 dv 集合,只保留設備編號有效的項目 @@ -1959,7 +1985,7 @@ SET FOREIGN_KEY_CHECKS = 1;"; /// /// /// - public async Task DeviceControlPoint (List dcp) + public async Task DeviceControlPoint(List dcp) { stopwatch = new Stopwatch(); stopwatch.Start();