[Backend]因應巨蛋棟同步失敗,優化同步程式

This commit is contained in:
張家睿 2025-03-28 17:13:18 +08:00
parent 85b8afb253
commit f6c1f28693

View File

@ -90,11 +90,11 @@ namespace Repository.BackendRepository.Implement
{ {
tag_name = x.Key.tag_name2, tag_name = x.Key.tag_name2,
displayName = x.Key.displayName2 displayName = x.Key.displayName2
}); });
// StringBuilder sb = new StringBuilder(); // StringBuilder sb = new StringBuilder();
bool isDome = false; //是否為巨蛋案 bool isDome = false; //是否為巨蛋案
int count = 0; int count = 0;
stopwatchSection = new Stopwatch(); stopwatchSection = new Stopwatch();
stopwatchSection.Start(); stopwatchSection.Start();
foreach (var row in ds2) foreach (var row in ds2)
@ -125,7 +125,7 @@ namespace Repository.BackendRepository.Implement
{ {
if (arrTag.Length == 5) 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, 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('" + 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 row.tag_name + "', '" + //niagara_tags
@ -209,7 +209,7 @@ namespace Repository.BackendRepository.Implement
} }
} }
} }
/// <summary> /// <summary>
/// 獲取照明開關 是否在 device_node 層 /// 獲取照明開關 是否在 device_node 層
/// </summary> /// </summary>
@ -220,9 +220,9 @@ namespace Repository.BackendRepository.Implement
stopwatch.Start(); stopwatch.Start();
using (IDbConnection conn = GetDbConnection()) using (IDbConnection conn = GetDbConnection())
{ {
conn.Open(); conn.Open();
var sql = "select system_value from variable where system_type = 'module_light_switch' "; var sql = "select system_value from variable where system_type = 'module_light_switch' ";
var module_light_switch = conn.QueryAsync<string>(sql).Result.FirstOrDefault(); var module_light_switch = conn.QueryAsync<string>(sql).Result.FirstOrDefault();
conn.Close(); conn.Close();
stopwatch.Stop(); stopwatch.Stop();
await KeepTimeLog("getLightSwitchLevel", stopwatch.ElapsedMilliseconds); await KeepTimeLog("getLightSwitchLevel", stopwatch.ElapsedMilliseconds);
@ -250,7 +250,7 @@ namespace Repository.BackendRepository.Implement
{ {
stopwatchSection = new Stopwatch(); stopwatchSection = new Stopwatch();
stopwatchSection.Start(); stopwatchSection.Start();
foreach(var b in building) foreach (var b in building)
{ {
string sql = @"CREATE TABLE IF NOT EXISTS `import_niagara_item` ( string sql = @"CREATE TABLE IF NOT EXISTS `import_niagara_item` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
@ -281,7 +281,8 @@ namespace Repository.BackendRepository.Implement
stopwatchSection = new Stopwatch(); stopwatchSection = new Stopwatch();
stopwatchSection.Start(); stopwatchSection.Start();
ds = ds.GroupBy(x => new { ds = ds.GroupBy(x => new
{
device_area_tag = x.device_area_tag, device_area_tag = x.device_area_tag,
device_building_tag = x.device_building_tag, device_building_tag = x.device_building_tag,
device_system_tag = x.device_system_tag, device_system_tag = x.device_system_tag,
@ -304,7 +305,7 @@ namespace Repository.BackendRepository.Implement
foreach (var row in ds) 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) 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_area_tag + "', '" +
row.device_building_tag + "', '" + row.device_building_tag + "', '" +
row.device_system_tag + "', '" + row.device_system_tag + "', '" +
@ -446,7 +447,7 @@ namespace Repository.BackendRepository.Implement
{ {
conn.Close(); conn.Close();
} }
} }
} }
@ -456,376 +457,404 @@ namespace Repository.BackendRepository.Implement
/// <returns></returns> /// <returns></returns>
public async Task DeviceComparison(string LightSwitchLevel) public async Task DeviceComparison(string LightSwitchLevel)
{ {
stopwatch = new Stopwatch(); Stopwatch stopwatch = Stopwatch.StartNew();
stopwatch.Start();
using (IDbConnection conn = GetDbConnection()) using (IDbConnection conn = GetDbConnection())
{ {
conn.Open(); conn.Open();
try try
{ {
List<NiagaraTags> result; // 1. 取得需要新增的 NiagaraTags
StringBuilder sb = new StringBuilder(); Stopwatch sw1 = Stopwatch.StartNew();
StringBuilder sb2 = new StringBuilder(); string sqlGetNiagaraTags = @"
stopwatchSection = new Stopwatch(); SELECT m.*
stopwatchSection.Start(); FROM import_niagara_tag m
sb.Append($@"SELECT m.* WHERE NOT EXISTS (
FROM import_niagara_tag m SELECT 1
WHERE NOT EXISTS ( FROM device d
SELECT 1 WHERE m.niagara_tags = d.device_number
FROM device d );";
WHERE m.niagara_tags = d.device_number List<NiagaraTags> niagaraTagsToAdd = (await conn.QueryAsync<NiagaraTags>(sqlGetNiagaraTags)).ToList();
);"); sw1.Stop();
result = (await conn.QueryAsync<NiagaraTags>(sb.ToString())).ToList<NiagaraTags>(); await KeepTimeLog("filter device item from import_niagara_tag", sw1.ElapsedMilliseconds);
sb.Clear();
stopwatchSection.Stop();
await KeepTimeLog("filter device item from import_niagara_tag", stopwatchSection.ElapsedMilliseconds);
#region device, device_kind // 2. 新增 device 和 device_kind
stopwatchSection = new Stopwatch(); if (niagaraTagsToAdd.Count > 0)
stopwatchSection.Start();
int count = 0;
//新增至device, is_link = 1
if (result.Count > 0)
{ {
var result2 = result.GroupBy(x => new // 2.1. 新增 device
Stopwatch sw2 = Stopwatch.StartNew();
List<string> sqlInsertDeviceList = new List<string>();
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") if (LightSwitchLevel == "node" && data.device_name_tag == "L1" && data.device_serial_tag.Substring(0, 1) != "G")
{ {
// 燈具新增 device_node // 燈具新增 device_node
continue; continue;
} }
else {
sb.Append($@" insert device(device_guid, deleted, status, priority, is_link, device_area_tag, string sqlInsertDevice = @"
device_building_tag, device_system_tag, device_name_tag, full_name, device_floor_tag, device_master, INSERT INTO device (device_guid, deleted, status, priority, is_link, device_area_tag,
device_last_name, device_serial_tag, device_model_tag, device_number, device_system_category_layer3, visible, created_at, updated_at) device_building_tag, device_system_tag, device_name_tag, full_name, device_floor_tag, device_master,
values(uuid(), 0, 1, 0, 1, '" + device_last_name, device_serial_tag, device_model_tag, device_number, device_system_category_layer3, visible, created_at, updated_at)
data.device_area_tag + "', '" + VALUES (uuid(), 0, 1, 0, 1, @device_area_tag, @device_building_tag, @device_system_tag, @device_name_tag,
data.device_building_tag + "', '" + @full_name, @device_floor_tag, @device_master_tag, @device_last_name_tag, @device_serial_tag,
data.device_system_tag + "', '" + @device_model_tag, @niagara_tags, @device_system_tag, 1, now(), now());";
data.device_name_tag + "', '" +
data.device_full_name + "', '" + sqlInsertDeviceList.Add(sqlInsertDevice); // 先暫存SQL語法等等一次執行
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;
}
}
} }
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<object> parameters = new List<object>();
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)) 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", 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<device_kind>(sqlString.ToString())).ToList<device_kind>();
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;
}
} }
} }
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)) x.device_building_tag,
{ x.device_system_tag,
await conn.ExecuteAsync(sb2.ToString()); x.device_name_tag
} }).Select(g => new
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<NiagaraTags>($@"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<device_kind>(sqlString.ToString())).ToList<device_kind>();
if (dk.Count == 0)
{ {
sb2.Append($@"INSERT device_kind (device_kind_guid, device_building_tag, device_system_tag, device_name_tag, g.Key.device_building_tag,
device_normal_flashing, device_close_flashing, device_error_flashing, device_error_independent, g.Key.device_system_tag,
created_by, created_at, device_model_tag, is_link) g.Key.device_name_tag
VALUES (uuid(), '" + data.device_building_tag + "', '" + data.device_system_tag + "', '" + data.device_name_tag + }).ToList();
"', 0, 0, 1, 0, 'B43E3CA7-96DD-4FC7-B6E6-974ACC3B0878', now(), '" + data.device_model_tag + "', 1);");
count += 1; foreach (var data in deviceKindData)
if (count >= 100) {
// 檢查 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<bool>(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)) 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<NiagaraTags>(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<bool>(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) sw5.Stop();
{ await KeepTimeLog("insert cctv device_kind", sw5.ElapsedMilliseconds);
using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled))
{
await conn.ExecuteAsync(sb2.ToString());
}
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)) using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled))
{ {
await conn.ExecuteAsync($@"SET SQL_SAFE_UPDATES = 0; await conn.ExecuteAsync(sqlUpdateDeviceKindIsLinkToZero); // 使用參數化查詢
UPDATE device_kind dk scope.Complete();
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;");
} }
// 再更新 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)) using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled))
{ {
await conn.ExecuteAsync($@"SET SQL_SAFE_UPDATES = 0; await conn.ExecuteAsync(sqlUpdateDeviceKindIsLinkToOne); // 使用參數化查詢
UPDATE device_kind dk scope.Complete();
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;");
} }
stopwatchSection.Stop();
await KeepTimeLog("insert/update cctv model is_link", stopwatchSection.ElapsedMilliseconds);
#endregion
#region device_node sw6.Stop();
stopwatchSection = new Stopwatch(); await KeepTimeLog("insert/update cctv model is_link", sw6.ElapsedMilliseconds);
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<NiagaraTags>(sb.ToString())).ToList<NiagaraTags>();
sb.Clear();
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<NiagaraTags> niagaraTagsToAddForNode = (await conn.QueryAsync<NiagaraTags>(sqlGetNiagaraTagsForNode)).ToList();
if (niagaraTagsToAddForNode.Count > 0)
{ {
var result2 = result.GroupBy(x => new // 4.1. 新增 device_node
List<string> sqlInsertDeviceNodeList = new List<string>();
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") if (LightSwitchLevel == "node" && data.device_name_tag == "L1" && data.device_serial_tag.Substring(0, 1) != "G")
{ {
// 燈具新增 device_node // 燈具新增 device_node
sb.Append($@"INSERT INTO device_node(device_node_guid, deleted, device_guid, device_number, full_name, created_by, created_at, updated_at) string sqlInsertDeviceNode = @"
VALUES (uuid(), 0, '' " + //device_guid 父層需要 forge 那邊提供 INSERT INTO device_node (device_node_guid, deleted, device_guid, device_number, full_name, created_by, created_at, updated_at)
",'" + data.niagara_tags + // device_number VALUES (uuid(), 0, '', @device_number, @full_name, 'B43E3CA7-96DD-4FC7-B6E6-974ACC3B0878', now(), now());";
"', '" + data.device_full_name + //full_name sqlInsertDeviceNodeList.Add(sqlInsertDeviceNode);
"','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;
}
} }
} }
//4.1.1 分批執行新增device node
if (sb.Length > 0) int batchSizeNode = 100;
for (int i = 0; i < sqlInsertDeviceNodeList.Count; i += batchSizeNode)
{ {
//建立參數
var batch = niagaraTagsToAddForNode.Skip(i).Take(batchSizeNode).ToList();
//建立參數化查詢要用的物件
List<object> parameters = new List<object>();
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)) 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(); // 5. 更新 device 的 is_link
stopwatchSection.Start(); Stopwatch sw8 = Stopwatch.StartNew();
//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);
stopwatchSection = new Stopwatch(); // 先更新 device 的 is_link 為 1 (邏輯簡單,直接使用 UPDATE JOIN)
stopwatchSection.Start(); string sqlUpdateDeviceIsLinkToOne = @"
// device_node 有, niagara沒有, is_link 更新成 0 UPDATE device d
sb.Append($@" SET SQL_SAFE_UPDATES = 0; JOIN import_niagara_tag i ON d.device_number = i.niagara_tags
UPDATE device_node dn SET d.is_link = 1, d.deleted = 0;";
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;");
using (TransactionScope scope = new TransactionScope((TransactionScopeOption)TransactionScopeAsyncFlowOption.Enabled)) 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(); stopwatch.Stop();
await KeepTimeLog("DeviceComparison", stopwatch.ElapsedMilliseconds); await KeepTimeLog("DeviceComparison", stopwatch.ElapsedMilliseconds);
} }
catch (Exception exception) catch (Exception exception)
{ {
//throw exception; throw; // 保留原始堆疊追蹤
throw;
} }
finally finally
{ {
conn.Close(); if (conn.State == ConnectionState.Open)
{
conn.Close();
}
} }
} }
} }
@ -1335,7 +1364,7 @@ namespace Repository.BackendRepository.Implement
throw exception; throw exception;
} }
finally finally
{ {
conn.Close(); conn.Close();
} }
} }
@ -1356,7 +1385,8 @@ namespace Repository.BackendRepository.Implement
try try
{ {
StringBuilder sb = new StringBuilder(); 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()); await conn.ExecuteAsync(sb.ToString());
} }
catch (Exception exception) catch (Exception exception)
@ -1424,17 +1454,13 @@ namespace Repository.BackendRepository.Implement
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.Append(@"SET SQL_SAFE_UPDATES = 0; sb.Append(@"SET SQL_SAFE_UPDATES = 0;
update device d
JOIN ( UPDATE device AS d
select niagara_tags, device_full_name from import_niagara_tag limit 100000 JOIN import_niagara_tag AS i ON d.device_number = i.niagara_tags
) m ON m.niagara_tags = d.device_number SET d.full_name = i.device_full_name
LEFT JOIN ( WHERE d.full_name <> i.device_full_name;
SELECT niagara_tags, device_full_name
FROM import_niagara_tag SET SQL_SAFE_UPDATES = 1;");
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;");
await conn.ExecuteAsync(sb.ToString()); await conn.ExecuteAsync(sb.ToString());
} }
catch (Exception exception) catch (Exception exception)
@ -1591,7 +1617,7 @@ namespace Repository.BackendRepository.Implement
conn.Close(); conn.Close();
} }
} }
stopwatchSection = new Stopwatch(); stopwatchSection = new Stopwatch();
stopwatchSection.Start(); stopwatchSection.Start();
// 過濾 dv 集合,只保留設備編號有效的項目 // 過濾 dv 集合,只保留設備編號有效的項目
@ -1959,7 +1985,7 @@ SET FOREIGN_KEY_CHECKS = 1;";
/// </summary> /// </summary>
/// <param name="dcp"></param> /// <param name="dcp"></param>
/// <returns></returns> /// <returns></returns>
public async Task DeviceControlPoint (List<DeviceControlPoint> dcp) public async Task DeviceControlPoint(List<DeviceControlPoint> dcp)
{ {
stopwatch = new Stopwatch(); stopwatch = new Stopwatch();
stopwatch.Start(); stopwatch.Start();