diff --git a/App.xaml.cs b/App.xaml.cs index 6edc193..ecce532 100644 --- a/App.xaml.cs +++ b/App.xaml.cs @@ -64,9 +64,9 @@ public partial class App : Application // 初始化数据处理链 var dataProcessingService = Host.Services.GetRequiredService(); dataProcessingService.AddProcessor(Host.Services.GetRequiredService()); - dataProcessingService.AddProcessor(Host.Services.GetRequiredService()); + dataProcessingService.AddProcessor(Host.Services.GetRequiredService()); dataProcessingService.AddProcessor(Host.Services.GetRequiredService()); - dataProcessingService.AddProcessor(Host.Services.GetRequiredService()); + dataProcessingService.AddProcessor(Host.Services.GetRequiredService()); } catch (Exception exception) { @@ -115,9 +115,9 @@ public partial class App : Application services.AddSingleton(); services.AddHostedService(provider => (DataProcessingService)provider.GetRequiredService()); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); // 注册数据仓库 services.AddSingleton(); @@ -247,13 +247,11 @@ public partial class App : Application _db.CodeFirst.InitTables(); _db.CodeFirst.InitTables(); _db.CodeFirst.InitTables(); - _db.CodeFirst.InitTables(); - _db.CodeFirst.InitTables(); - _db.CodeFirst.InitTables(); + _db.CodeFirst.InitTables(); + _db.CodeFirst.InitTables(); _db.CodeFirst.InitTables(); _db.CodeFirst.InitTables(); _db.CodeFirst.InitTables(); - // _db.CodeFirst.InitTables(); _db.CodeFirst.InitTables(); } } \ No newline at end of file diff --git a/Data/Entities/DbVariableData.cs b/Data/Entities/DbVariable.cs similarity index 96% rename from Data/Entities/DbVariableData.cs rename to Data/Entities/DbVariable.cs index 52b76f3..111e7d0 100644 --- a/Data/Entities/DbVariableData.cs +++ b/Data/Entities/DbVariable.cs @@ -8,7 +8,7 @@ namespace PMSWPF.Data.Entities; /// 表示数据库中的变量数据实体。 /// [SugarTable("VarData")] -public class DbVariableData +public class DbVariable { /// /// 变量唯一标识符。 @@ -161,12 +161,12 @@ public class DbVariableData /// /// 关联的MQTT配置列表。 /// - [Navigate(NavigateType.OneToMany, nameof(DbVariableMqtt.VariableDataId))] + [Navigate(NavigateType.OneToMany, nameof(DbVariableMqtt.VariableId))] public List? VariableMqtts { get; set; } /// /// 关联的历史记录列表。 /// - [Navigate(NavigateType.OneToMany, nameof(DbVariableDataHistory.VariableDataId))] - public List? HistoryRecords { get; set; } + [Navigate(NavigateType.OneToMany, nameof(DbVariableHistory.VariableId))] + public List? HistoryRecords { get; set; } } \ No newline at end of file diff --git a/Data/Entities/DbVariableDataHistory.cs b/Data/Entities/DbVariableHistory.cs similarity index 84% rename from Data/Entities/DbVariableDataHistory.cs rename to Data/Entities/DbVariableHistory.cs index a2e78aa..de91ac1 100644 --- a/Data/Entities/DbVariableDataHistory.cs +++ b/Data/Entities/DbVariableHistory.cs @@ -7,7 +7,7 @@ namespace PMSWPF.Data.Entities; /// 表示数据库中的变量数据历史实体。 /// [SugarTable("VarDataHistory")] -public class DbVariableDataHistory +public class DbVariableHistory { /// /// 历史记录唯一标识符。 @@ -34,13 +34,13 @@ public class DbVariableDataHistory /// /// 关联的DbVariableData的ID。 /// - public int VariableDataId { get; set; } + public int VariableId { get; set; } /// /// 关联的DbVariableData实体。 /// - [Navigate(NavigateType.ManyToOne, nameof(VariableDataId))] - public DbVariableData? VariableData { get; set; } + [Navigate(NavigateType.ManyToOne, nameof(VariableId))] + public DbVariable? Variable { get; set; } /// /// 历史记录的时间戳。 diff --git a/Data/Entities/DbVariableMqtt.cs b/Data/Entities/DbVariableMqtt.cs index 486647b..5536dda 100644 --- a/Data/Entities/DbVariableMqtt.cs +++ b/Data/Entities/DbVariableMqtt.cs @@ -18,7 +18,7 @@ public class DbVariableMqtt /// /// 关联的变量数据ID。 /// - public int VariableDataId { get; set; } + public int VariableId { get; set; } /// /// 关联的MQTT服务器ID。 @@ -43,8 +43,8 @@ public class DbVariableMqtt /// /// 导航属性:关联的变量数据。 /// - [Navigate(NavigateType.ManyToOne, nameof(VariableDataId))] - public DbVariableData? VariableData { get; set; } + [Navigate(NavigateType.ManyToOne, nameof(VariableId))] + public DbVariable? Variable { get; set; } /// /// 导航属性:关联的MQTT服务器。 diff --git a/Data/Entities/DbVariableS7Data.cs b/Data/Entities/DbVariableS7Data.cs deleted file mode 100644 index d6687f3..0000000 --- a/Data/Entities/DbVariableS7Data.cs +++ /dev/null @@ -1,11 +0,0 @@ -using SqlSugar; - -namespace PMSWPF.Data.Entities; - -/// -/// 表示数据库中的S7变量数据实体,继承自DbVariableData。 -/// -[SugarTable("S7DataVariable")] -public class DbVariableS7Data : DbVariableData -{ -} \ No newline at end of file diff --git a/Data/Entities/DbVariableTable.cs b/Data/Entities/DbVariableTable.cs index 88dca82..8aeb455 100644 --- a/Data/Entities/DbVariableTable.cs +++ b/Data/Entities/DbVariableTable.cs @@ -13,8 +13,8 @@ public class DbVariableTable /// /// 变量表中包含的数据变量列表。 /// - [Navigate(NavigateType.OneToMany, nameof(DbVariableData.VariableTableId))] - public List? DataVariables { get; set; } + [Navigate(NavigateType.OneToMany, nameof(DbVariable.VariableTableId))] + public List? Variables { get; set; } /// /// 变量表关联的设备。 diff --git a/Data/Repositories/DeviceRepository.cs b/Data/Repositories/DeviceRepository.cs index 73daa7b..18ee837 100644 --- a/Data/Repositories/DeviceRepository.cs +++ b/Data/Repositories/DeviceRepository.cs @@ -72,7 +72,7 @@ public class DeviceRepository stopwatch.Start(); var dlist = await db.Queryable() .Includes(d => d.VariableTables, dv => dv.Device) - .Includes(d => d.VariableTables, dvd => dvd.DataVariables, data => data.VariableTable) + .Includes(d => d.VariableTables, dvd => dvd.Variables, data => data.VariableTable) .ToListAsync(); diff --git a/Data/Repositories/MqttRepository.cs b/Data/Repositories/MqttRepository.cs index 1851e6b..876d5d9 100644 --- a/Data/Repositories/MqttRepository.cs +++ b/Data/Repositories/MqttRepository.cs @@ -53,7 +53,7 @@ public class MqttRepository using (var _db = DbContext.GetInstance()) { var result = await _db.Queryable() - .Includes(m => m.VariableMqtts, vm => vm.VariableData) + .Includes(m => m.VariableMqtts, vm => vm.Variable) .Includes(m => m.VariableMqtts, vm => vm.Mqtt) .ToListAsync(); stopwatch.Stop(); diff --git a/Data/Repositories/VarDataRepository.cs b/Data/Repositories/VarDataRepository.cs index 850bfe2..84fb7c3 100644 --- a/Data/Repositories/VarDataRepository.cs +++ b/Data/Repositories/VarDataRepository.cs @@ -7,6 +7,7 @@ using PMSWPF.Helper; using PMSWPF.Models; using SqlSugar; using AutoMapper; +using Dm.util; namespace PMSWPF.Data.Repositories; @@ -27,7 +28,7 @@ public class VarDataRepository /// /// 主键ID /// - public async Task GetByIdAsync(int id) + public async Task GetByIdAsync(int id) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); @@ -46,9 +47,9 @@ public class VarDataRepository /// 主键ID /// SqlSugarClient实例 /// - public async Task GetByIdAsync(int id, SqlSugarClient db) + public async Task GetByIdAsync(int id, SqlSugarClient db) { - return await db.Queryable() + return await db.Queryable() .In(id) .SingleAsync(); } @@ -57,7 +58,7 @@ public class VarDataRepository /// 获取所有VariableData /// /// - public async Task> GetAllAsync() + public async Task> GetAllAsync() { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); @@ -75,13 +76,13 @@ public class VarDataRepository /// /// SqlSugarClient实例 /// - public async Task> GetAllAsync(SqlSugarClient db) + public async Task> GetAllAsync(SqlSugarClient db) { - var result = await db.Queryable() + var result = await db.Queryable() .Includes(d => d.VariableTable) .Includes(d => d.VariableTable.Device) .ToListAsync(); - return result.Select(d => _mapper.Map(d)) + return result.Select(d => _mapper.Map(d)) .ToList(); } @@ -89,7 +90,7 @@ public class VarDataRepository /// 获取所有VariableData /// /// - public async Task> GetByVariableTableIdAsync(int varTableId) + public async Task> GetByVariableTableIdAsync(int varTableId) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); @@ -107,29 +108,29 @@ public class VarDataRepository /// /// SqlSugarClient实例 /// - public async Task> GetByVariableTableIdAsync(int varTableId, SqlSugarClient db) + public async Task> GetByVariableTableIdAsync(int varTableId, SqlSugarClient db) { - var result = await db.Queryable() + var result = await db.Queryable() .Where(d => d.VariableTableId == varTableId) .ToListAsync(); - return result.Select(d => _mapper.Map(d)) + return result.Select(d => _mapper.Map(d)) .ToList(); } /// /// 新增VariableData /// - /// VariableData实体 + /// VariableData实体 /// - public async Task AddAsync(VariableData variableData) + public async Task AddAsync(Variable variable) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); using (var db = DbContext.GetInstance()) { - var varData = await AddAsync(variableData, db); + var varData = await AddAsync(variable, db); stopwatch.Stop(); - NlogHelper.Info($"新增VariableData '{variableData.Name}' 耗时:{stopwatch.ElapsedMilliseconds}ms"); + NlogHelper.Info($"新增VariableData '{variable.Name}' 耗时:{stopwatch.ElapsedMilliseconds}ms"); return varData; } } @@ -138,17 +139,17 @@ public class VarDataRepository /// /// 新增VariableData /// - /// VariableData实体 + /// VariableData实体 /// - public async Task AddAsync(VariableData variableData, SqlSugarClient db) + public async Task AddAsync(Variable variable, SqlSugarClient db) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); - var dbVarData = await db.Insertable(_mapper.Map(variableData)) + var dbVarData = await db.Insertable(_mapper.Map(variable)) .ExecuteReturnEntityAsync(); stopwatch.Stop(); - NlogHelper.Info($"新增VariableData '{variableData.Name}' 耗时:{stopwatch.ElapsedMilliseconds}ms"); - return _mapper.Map(dbVarData); + NlogHelper.Info($"新增VariableData '{variable.Name}' 耗时:{stopwatch.ElapsedMilliseconds}ms"); + return _mapper.Map(dbVarData); } /// @@ -156,7 +157,7 @@ public class VarDataRepository /// /// VariableData实体 /// - public async Task AddAsync(IEnumerable variableDatas) + public async Task AddAsync(IEnumerable variableDatas) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); @@ -175,18 +176,18 @@ public class VarDataRepository /// /// VariableData实体 /// - public async Task AddAsync(IEnumerable variableDatas, SqlSugarClient db) + public async Task AddAsync(IEnumerable variableDatas, SqlSugarClient db) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); Stopwatch stopwatch2 = new Stopwatch(); stopwatch2.Start(); - var dbList = variableDatas.Select(vb => _mapper.Map(vb)) + var dbList = variableDatas.Select(vb => _mapper.Map(vb)) .ToList(); stopwatch2.Stop(); - NlogHelper.Info($"复制 VariableData'{variableDatas.Count()}'个, 耗时:{stopwatch2.ElapsedMilliseconds}ms"); + NlogHelper.Info($"复制 Variable'{variableDatas.Count()}'个, 耗时:{stopwatch2.ElapsedMilliseconds}ms"); - var res = await db.Insertable(dbList) + var res = await db.Insertable(dbList) .ExecuteCommandAsync(); stopwatch.Stop(); @@ -198,17 +199,17 @@ public class VarDataRepository /// /// 更新VariableData /// - /// VariableData实体 + /// VariableData实体 /// - public async Task UpdateAsync(VariableData variableData) + public async Task UpdateAsync(Variable variable) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); using (var db = DbContext.GetInstance()) { - var result = await UpdateAsync(variableData, db); + var result = await UpdateAsync(variable, db); stopwatch.Stop(); - NlogHelper.Info($"更新VariableData '{variableData.Name}' 耗时:{stopwatch.ElapsedMilliseconds}ms"); + NlogHelper.Info($"更新VariableData '{variable.Name}' 耗时:{stopwatch.ElapsedMilliseconds}ms"); return result; } } @@ -216,12 +217,12 @@ public class VarDataRepository /// /// 更新VariableData /// - /// VariableData实体 + /// VariableData实体 /// SqlSugarClient实例 /// - public async Task UpdateAsync(VariableData variableData, SqlSugarClient db) + public async Task UpdateAsync(Variable variable, SqlSugarClient db) { - var result = await db.Updateable(_mapper.Map(variableData)) + var result = await db.Updateable(_mapper.Map(variable)) .ExecuteCommandAsync(); return result; } @@ -231,7 +232,7 @@ public class VarDataRepository /// /// VariableData实体 /// - public async Task UpdateAsync(List variableDatas) + public async Task UpdateAsync(List variableDatas) { using var _db = DbContext.GetInstance(); return await UpdateAsync(variableDatas, _db); @@ -242,13 +243,13 @@ public class VarDataRepository /// /// VariableData实体 /// - public async Task UpdateAsync(List variableDatas, SqlSugarClient db) + public async Task UpdateAsync(List variableDatas, SqlSugarClient db) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); - var dbVarDatas = variableDatas.Select(vd => _mapper.Map(vd)); - var result = await db.Updateable(dbVarDatas.ToList()) + var dbVarDatas = variableDatas.Select(vd => _mapper.Map(vd)); + var result = await db.Updateable(dbVarDatas.ToList()) .ExecuteCommandAsync(); stopwatch.Stop(); @@ -261,14 +262,14 @@ public class VarDataRepository /// /// 主键ID /// - public async Task DeleteAsync(VariableData variableData) + public async Task DeleteAsync(Variable variable) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); using var db = DbContext.GetInstance(); - var result = await DeleteAsync(variableData, db); + var result = await DeleteAsync(variable, db); stopwatch.Stop(); - NlogHelper.Info($"删除VariableData: '{variableData.Name}' 耗时:{stopwatch.ElapsedMilliseconds}ms"); + NlogHelper.Info($"删除VariableData: '{variable.Name}' 耗时:{stopwatch.ElapsedMilliseconds}ms"); return result; } @@ -278,10 +279,10 @@ public class VarDataRepository /// 主键ID /// SqlSugarClient实例 /// - public async Task DeleteAsync(VariableData variableData, SqlSugarClient db) + public async Task DeleteAsync(Variable variable, SqlSugarClient db) { - var result = await db.Deleteable() - .Where(d => d.Id == variableData.Id) + var result = await db.Deleteable() + .Where(d => d.Id == variable.Id) .ExecuteCommandAsync(); return result; } @@ -291,7 +292,7 @@ public class VarDataRepository /// /// 主键ID /// - public async Task DeleteAsync(IEnumerable variableDatas) + public async Task DeleteAsync(IEnumerable variableDatas) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); @@ -310,11 +311,11 @@ public class VarDataRepository /// 主键ID /// SqlSugarClient实例 /// - public async Task DeleteAsync(IEnumerable variableDatas, SqlSugarClient db) + public async Task DeleteAsync(IEnumerable variableDatas, SqlSugarClient db) { - var dbList = variableDatas.Select(vd => _mapper.Map(vd)) + var dbList = variableDatas.Select(vd => _mapper.Map(vd)) .ToList(); - var result = await db.Deleteable(dbList) + var result = await db.Deleteable(dbList) .ExecuteCommandAsync(); return result; } @@ -330,56 +331,79 @@ public class VarDataRepository /// /// 要添加MQTT服务器的变量数据列表。 /// 成功添加或更新关联的数量。 - public async Task AddMqttToVariablesAsync(IEnumerable variableMqttList) + public async Task AddMqttToVariablesAsync(IEnumerable variableMqttList) { - Stopwatch stopwatch = new Stopwatch(); - stopwatch.Start(); - int affectedCount = 0; using var db = DbContext.GetInstance(); - //插入列表 - List insertDbVM = new List(); + await db.BeginTranAsync(); - foreach (var variableMqtt in variableMqttList) + try { - var existingAlias = await db.Queryable() - .Where(it => it.VariableDataId == variableMqtt.VariableData.Id && it.MqttId == variableMqtt.Mqtt.Id) - .FirstAsync(); - if (existingAlias == null) - { - // 如果不存在,则添加新的关联 - insertDbVM.Add(new DbVariableMqtt - { - VariableDataId = variableMqtt.VariableData.Id, - MqttId = variableMqtt.Mqtt.Id, - MqttAlias = variableMqtt.MqttAlias, - CreateTime = DateTime.Now, - UpdateTime = DateTime.Now - }); - - affectedCount++; - } - else if (existingAlias.MqttAlias !=variableMqtt.MqttAlias) - { - // 如果存在但别名不同,则更新别名 - await db.Updateable() - .SetColumns(it => it.MqttAlias == variableMqtt.MqttAlias) - .Where(it => it.VariableDataId == variableMqtt.VariableData.Id && it.MqttId == variableMqtt.Mqtt.Id) - .ExecuteCommandAsync(); - NlogHelper.Info( - $"为 {variableMqtt.VariableData.Name} 变量更新MQTT服务器{variableMqtt.Mqtt.Name}关联."); - affectedCount++; - } - } + int affectedCount = 0; + var variableIds = variableMqttList.Select(vm => vm.Variable.Id).Distinct().ToList(); + var mqttIds = variableMqttList.Select(vm => vm.Mqtt.Id).Distinct().ToList(); - if (insertDbVM.Count > 0) + // 1. 一次性查询所有相关的现有别名 + var existingAliases = await db.Queryable() + .Where(it => variableIds.Contains(it.VariableId) && mqttIds.Contains(it.MqttId)) + .ToListAsync(); + + var existingAliasesDict = existingAliases + .ToDictionary(a => (a.VariableId, a.MqttId), a => a); + + var toInsert = new List(); + var toUpdate = new List(); + + foreach (var variableMqtt in variableMqttList) + { + var key = (variableMqtt.Variable.Id, variableMqtt.Mqtt.Id); + if (existingAliasesDict.TryGetValue(key, out var existingAlias)) + { + // 如果存在但别名不同,则准备更新 + if (existingAlias.MqttAlias != variableMqtt.MqttAlias) + { + existingAlias.MqttAlias = variableMqtt.MqttAlias; + existingAlias.UpdateTime = DateTime.Now; + toUpdate.Add(existingAlias); + } + } + else + { + // 如果不存在,则准备插入 + toInsert.Add(new DbVariableMqtt + { + VariableId = variableMqtt.Variable.Id, + MqttId = variableMqtt.Mqtt.Id, + MqttAlias = variableMqtt.MqttAlias, + CreateTime = DateTime.Now, + UpdateTime = DateTime.Now + }); + } + } + + // 2. 批量更新 + if (toUpdate.Any()) + { + var updateResult = await db.Updateable(toUpdate).ExecuteCommandAsync(); + affectedCount += updateResult; + } + + // 3. 批量插入 + if (toInsert.Any()) + { + var insertResult = await db.Insertable(toInsert).ExecuteCommandAsync(); + affectedCount += insertResult; + } + + await db.CommitTranAsync(); + NlogHelper.Info($"成功为 {variableMqttList.Count()} 个变量请求添加/更新了MQTT服务器关联,实际影响 {affectedCount} 个。"); + return affectedCount; + } + catch (Exception ex) { - await db.Insertable(insertDbVM).ExecuteCommandAsync(); - NlogHelper.Info( - $"为 {insertDbVM.Count} 个变量添加MQTT服务器 关联,成功影响 {affectedCount} 个,耗时:{stopwatch.ElapsedMilliseconds}ms"); + await db.RollbackTranAsync(); + NlogHelper.Error($"为变量添加MQTT服务器关联时发生错误: {ex.Message}", ex); + // 根据需要,可以向上层抛出异常 + throw; } - - stopwatch.Stop(); - - return affectedCount; } } \ No newline at end of file diff --git a/Data/Repositories/VariableMqttAliasRepository.cs b/Data/Repositories/VariableMqttAliasRepository.cs index 004bf50..f1a5325 100644 --- a/Data/Repositories/VariableMqttAliasRepository.cs +++ b/Data/Repositories/VariableMqttAliasRepository.cs @@ -34,7 +34,7 @@ public class VariableMqttAliasRepository public async Task GetAliasByVariableAndMqtt(int variableDataId, int mqttId, SqlSugarClient db) { return await db.Queryable() - .Where(it => it.VariableDataId == variableDataId && it.MqttId == mqttId) + .Where(it => it.VariableId == variableDataId && it.MqttId == mqttId) .FirstAsync(); } @@ -89,7 +89,7 @@ public class VariableMqttAliasRepository { return await db.Updateable() .SetColumns(it => it.MqttAlias == newAlias) - .Where(it => it.VariableDataId == variableDataId && it.MqttId == mqttId) + .Where(it => it.VariableId == variableDataId && it.MqttId == mqttId) .ExecuteCommandAsync(); } @@ -117,7 +117,7 @@ public class VariableMqttAliasRepository public async Task DeleteAsync(int variableDataId, int mqttId, SqlSugarClient db) { return await db.Deleteable() - .Where(it => it.VariableDataId == variableDataId && it.MqttId == mqttId) + .Where(it => it.VariableId == variableDataId && it.MqttId == mqttId) .ExecuteCommandAsync(); } } diff --git a/Extensions/ObjectExtensions.cs b/Extensions/ObjectExtensions.cs index edabfaa..e07e618 100644 --- a/Extensions/ObjectExtensions.cs +++ b/Extensions/ObjectExtensions.cs @@ -94,9 +94,9 @@ public static class ObjectExtensions // 特殊处理 Mqtts 列表的复制 if (sourceProperty.Name == "Mqtts") { - if (sourceType == typeof(VariableData) && targetType == typeof(DbVariableData)) + if (sourceType == typeof(Variable) && targetType == typeof(DbVariable)) { - // 从 VariableData (List) 转换为 DbVariableData (List) + // 从 Variable (List) 转换为 DbVariable (List) var sourceMqtts = sourceValue as List; if (sourceMqtts != null) { @@ -108,9 +108,9 @@ public static class ObjectExtensions targetProperty.SetValue(ttarget, null); } } - else if (sourceType == typeof(DbVariableData) && targetType == typeof(VariableData)) + else if (sourceType == typeof(DbVariable) && targetType == typeof(Variable)) { - // 从 DbVariableData (List) 转换为 VariableData (List) + // 从 DbVariable (List) 转换为 Variable (List) var sourceDbMqtts = sourceValue as List; if (sourceDbMqtts != null) { diff --git a/Helper/ExcelHelper.cs b/Helper/ExcelHelper.cs index bb5e6cd..66c6f3a 100644 --- a/Helper/ExcelHelper.cs +++ b/Helper/ExcelHelper.cs @@ -161,7 +161,7 @@ namespace PMSWPF.Helper /// /// /// - public static List ImprotFromTiaVariableTable(string excelFilePath) + public static List ImprotFromTiaVariableTable(string excelFilePath) { // Act // _testFilePath = "C:\\Users\\Administrator\\Desktop\\浓度变量.xlsx"; @@ -173,22 +173,22 @@ namespace PMSWPF.Helper "Excel表格式不正确:第一列的名字是:Name,第三列的名字是:Data Type,Data Type,第四列的名字是:Logical Address,请检查"); - List variableDatas = new List(); + List variableDatas = new List(); foreach (DataRow dataRow in dataTable.Rows) { - VariableData variableData = new VariableData(); - variableData.Name=dataRow["Name"].ToString(); - variableData.DataType=SiemensHelper.S7ToCSharpTypeString(dataRow["Data Type"].ToString()) ; + Variable variable = new Variable(); + variable.Name=dataRow["Name"].ToString(); + variable.DataType=SiemensHelper.S7ToCSharpTypeString(dataRow["Data Type"].ToString()) ; var exS7Addr=dataRow["Logical Address"].ToString(); if (exS7Addr.StartsWith("%")) { - variableData.S7Address = exS7Addr.Substring(1); + variable.S7Address = exS7Addr.Substring(1); } - variableData.NodeId = ""; - variableData.ProtocolType = ProtocolType.S7; - variableData.SignalType = SignalType.OtherASignal; - variableDatas.Add(variableData); + variable.NodeId = ""; + variable.ProtocolType = ProtocolType.S7; + variable.SignalType = SignalType.OtherASignal; + variableDatas.Add(variable); } return variableDatas; diff --git a/Models/VariableData.cs b/Models/Variable.cs similarity index 97% rename from Models/VariableData.cs rename to Models/Variable.cs index bfbfbb5..c3441d3 100644 --- a/Models/VariableData.cs +++ b/Models/Variable.cs @@ -6,7 +6,7 @@ namespace PMSWPF.Models; /// /// 表示变量数据信息。 /// -public partial class VariableData : ObservableObject, IEquatable +public partial class Variable : ObservableObject, IEquatable { /// /// 变量唯一标识符。 @@ -184,10 +184,10 @@ public partial class VariableData : ObservableObject, IEquatable public override bool Equals(object? obj) { - return Equals(obj as VariableData); + return Equals(obj as Variable); } - public bool Equals(VariableData? other) + public bool Equals(Variable? other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; diff --git a/Models/VariableDataContext.cs b/Models/VariableContext.cs similarity index 59% rename from Models/VariableDataContext.cs rename to Models/VariableContext.cs index 6c1ca0f..a001945 100644 --- a/Models/VariableDataContext.cs +++ b/Models/VariableContext.cs @@ -2,12 +2,12 @@ using PMSWPF.Models; namespace PMSWPF.Models { - public class VariableDataContext + public class VariableContext { - public VariableData Data { get; set; } + public Variable Data { get; set; } public bool IsHandled { get; set; } - public VariableDataContext(VariableData data) + public VariableContext(Variable data) { Data = data; IsHandled = false; // 默认未处理 diff --git a/Models/VariableMqtt.cs b/Models/VariableMqtt.cs index 0133b2f..d5b4a36 100644 --- a/Models/VariableMqtt.cs +++ b/Models/VariableMqtt.cs @@ -14,11 +14,11 @@ public partial class VariableMqtt : ObservableObject { } - public VariableMqtt(VariableData? variableData, Mqtt? mqtt) + public VariableMqtt(Variable variable, Mqtt mqtt) { - VariableData = variableData; + Variable = variable; Mqtt = mqtt; - MqttAlias = MqttAlias != String.Empty ? MqttAlias : variableData.Name; + MqttAlias = MqttAlias != String.Empty ? MqttAlias : variable.Name; } /// @@ -29,7 +29,7 @@ public partial class VariableMqtt : ObservableObject /// /// 关联的变量数据ID。 /// - public int VariableDataId { get; set; } + public int VariableId { get; set; } /// /// 关联的MQTT服务器ID。 @@ -49,13 +49,13 @@ public partial class VariableMqtt : ObservableObject { get { - if (VariableData.ProtocolType == ProtocolType.S7) + if (Variable.ProtocolType == ProtocolType.S7) { - return VariableData.S7Address; + return Variable.S7Address; } - else if (VariableData.ProtocolType == ProtocolType.OpcUA) + else if (Variable.ProtocolType == ProtocolType.OpcUA) { - return VariableData.OpcUaNodeId; + return Variable.OpcUaNodeId; } return string.Empty; @@ -75,10 +75,10 @@ public partial class VariableMqtt : ObservableObject /// /// 导航属性:关联的变量数据。 /// - public VariableData? VariableData { get; set; } + public Variable Variable { get; set; } /// /// 导航属性:关联的MQTT服务器。 /// - public Mqtt? Mqtt { get; set; } + public Mqtt Mqtt { get; set; } } \ No newline at end of file diff --git a/Models/VariableTable.cs b/Models/VariableTable.cs index 8ad57ed..d3c060e 100644 --- a/Models/VariableTable.cs +++ b/Models/VariableTable.cs @@ -30,17 +30,8 @@ public partial class VariableTable : ObservableObject /// 变量表中包含的数据变量列表。 /// [ObservableProperty] - public ObservableCollection dataVariables; - // [ObservableProperty] - // public ObservableCollection varDataList; - // - // // 列表改变了的事件 - // // public event Action> OnDataVariableListChanged; - // partial void OnDataVariablesChanged(List variableDatas) - // { - // VarDataList=new ObservableCollection(variableDatas); - // } - + public ObservableCollection variables; + /// /// 变量表的唯一标识符。 /// diff --git a/PMSWPF.Tests/ExcelHelperTests.cs b/PMSWPF.Tests/ExcelHelperTests.cs index 77fad39..e4e8669 100644 --- a/PMSWPF.Tests/ExcelHelperTests.cs +++ b/PMSWPF.Tests/ExcelHelperTests.cs @@ -98,23 +98,23 @@ namespace PMSWPF.Tests "Excel表格式不正确:第一列的名字是:Name,第三列的名字是:Data Type,Data Type,第四列的名字是:Logical Address,请检查"); - List variableDatas = new List(); + List variables = new List(); foreach (DataRow dataRow in dataTable.Rows) { - VariableData variableData = new VariableData(); - variableData.Name=dataRow["Name"].ToString(); - variableData.DataType=SiemensHelper.S7ToCSharpTypeString(dataRow["Data Type"].ToString()) ; + Variable variable = new Variable(); + variable.Name=dataRow["Name"].ToString(); + variable.DataType=SiemensHelper.S7ToCSharpTypeString(dataRow["Data Type"].ToString()) ; var exS7Addr=dataRow["Logical Address"].ToString(); if (exS7Addr.StartsWith("%")) { - variableData.S7Address = exS7Addr.Substring(1); + variable.S7Address = exS7Addr.Substring(1); } - variableData.ProtocolType = ProtocolType.S7; - variableData.SignalType = SignalType.OtherASignal; - variableDatas.Add(variableData); + variable.ProtocolType = ProtocolType.S7; + variable.SignalType = SignalType.OtherASignal; + variables.Add(variable); } - Assert.Greater(variableDatas.Count, 0); + Assert.Greater(variables.Count, 0); // Assert // Assert.AreEqual(2, result.Rows.Count);FDFD // Assert.AreEqual("1", result.Rows[0]["Id"]); diff --git a/Profiles/MappingProfile.cs b/Profiles/MappingProfile.cs index b01db1f..678ea48 100644 --- a/Profiles/MappingProfile.cs +++ b/Profiles/MappingProfile.cs @@ -22,7 +22,7 @@ public class MappingProfile : Profile // --- 变量表映射 (List中的元素) --- CreateMap().ReverseMap(); - CreateMap().ReverseMap(); + CreateMap().ReverseMap(); // --- MQTT 和 变量数据 映射 --- CreateMap().ReverseMap(); CreateMap().ReverseMap(); diff --git a/Services/DataProcessingService.cs b/Services/DataProcessingService.cs index 9e61ef3..81984b8 100644 --- a/Services/DataProcessingService.cs +++ b/Services/DataProcessingService.cs @@ -17,10 +17,10 @@ namespace PMSWPF.Services; public class DataProcessingService : BackgroundService, IDataProcessingService { // 使用 Channel 作为高性能的生产者/消费者队列 - private readonly Channel _queue; + private readonly Channel _queue; // 存储数据处理器的链表 - private readonly List _processors; + private readonly List _processors; /// /// 构造函数,注入日志记录器。 @@ -29,8 +29,8 @@ public class DataProcessingService : BackgroundService, IDataProcessingService public DataProcessingService() { // 创建一个无边界的 Channel,允许生产者快速写入而不会被阻塞。 - _queue = Channel.CreateUnbounded(); - _processors = new List(); + _queue = Channel.CreateUnbounded(); + _processors = new List(); } /// @@ -38,7 +38,7 @@ public class DataProcessingService : BackgroundService, IDataProcessingService /// 处理器将按照添加的顺序执行。 /// /// 要添加的数据处理器实例。 - public void AddProcessor(IVariableDataProcessor processor) + public void AddProcessor(IVariableProcessor processor) { _processors.Add(processor); } @@ -47,14 +47,14 @@ public class DataProcessingService : BackgroundService, IDataProcessingService /// 将一个变量数据项异步推入处理队列。 /// /// 要入队的变量数据。 - public async ValueTask EnqueueAsync(VariableData data) + public async ValueTask EnqueueAsync(Variable data) { if (data == null) { return; } - var context = new VariableDataContext(data); + var context = new VariableContext(data); // 将数据项写入 Channel,供后台服务处理。 await _queue.Writer.WriteAsync(context); } diff --git a/Services/DataServices.cs b/Services/DataServices.cs index 884c610..e143a97 100644 --- a/Services/DataServices.cs +++ b/Services/DataServices.cs @@ -31,7 +31,7 @@ public partial class DataServices : ObservableRecipient, IRecipient // 变量数据列表。 [ObservableProperty] - private List _variableDatas; + private List _variables; // 菜单树列表。 [ObservableProperty] @@ -42,7 +42,7 @@ public partial class DataServices : ObservableRecipient, IRecipient private List _mqtts; - public ConcurrentDictionary AllVariables; + public ConcurrentDictionary AllVariables; // 设备数据仓库,用于设备数据的CRUD操作。 private readonly DeviceRepository _deviceRepository; @@ -97,8 +97,8 @@ public partial class DataServices : ObservableRecipient, IRecipient _menuRepository = menuRepository; _mqttRepository = mqttRepository; _varDataRepository = varDataRepository; - _variableDatas = new List(); - AllVariables = new ConcurrentDictionary(); + _variables = new List(); + AllVariables = new ConcurrentDictionary(); } /// @@ -161,9 +161,9 @@ public partial class DataServices : ObservableRecipient, IRecipient } var allVar = await _varDataRepository.GetAllAsync(); - foreach (var variableData in allVar) + foreach (var variable in allVar) { - AllVariables.AddOrUpdate(variableData.Id, variableData, (key, old) => variableData); + AllVariables.AddOrUpdate(variable.Id, variable, (key, old) => variable); } } @@ -234,19 +234,19 @@ public partial class DataServices : ObservableRecipient, IRecipient /// 异步加载变量数据。 /// /// 表示异步操作的任务。 - private async Task LoadVariableDatas() + private async Task LoadVariables() { - VariableDatas = await _varDataRepository.GetAllAsync(); + Variables = await _varDataRepository.GetAllAsync(); } /// /// 异步更新变量数据。 /// - /// 要更新的变量数据。 + /// 要更新的变量数据。 /// 表示异步操作的任务。 - public async Task UpdateVariableDataAsync(VariableData variableData) + public async Task UpdateVariableAsync(Variable variable) { - await _varDataRepository.UpdateAsync(variableData); + await _varDataRepository.UpdateAsync(variable); } } \ No newline at end of file diff --git a/Services/DialogService.cs b/Services/DialogService.cs index 360f540..e6be0cb 100644 --- a/Services/DialogService.cs +++ b/Services/DialogService.cs @@ -11,11 +11,11 @@ namespace PMSWPF.Services; public class DialogService :IDialogService { - private readonly MqttRepository _mqttRepository; + private readonly DataServices _dataServices; - public DialogService(MqttRepository mqttRepository) + public DialogService(DataServices dataServices) { - _mqttRepository = mqttRepository; + _dataServices = dataServices; } public async Task ShowAddDeviceDialog() @@ -120,17 +120,17 @@ public class DialogService :IDialogService return null; } - public async Task ShowAddVarDataDialog() + public async Task ShowAddVarDataDialog() { VarDataDialogViewModel vm = new(); vm.Title = "添加变量"; vm.PrimaryButtonText = "添加变量"; - vm.VariableData = new VariableData(); + vm.Variable = new Variable(); var dialog = new VarDataDialog(vm); var res = await dialog.ShowAsync(); if (res == ContentDialogResult.Primary) { - return vm.VariableData; + return vm.Variable; } return null; } @@ -141,17 +141,17 @@ public class DialogService :IDialogService MessageBox.Show(message); } - public async Task ShowEditVarDataDialog(VariableData variableData) + public async Task ShowEditVarDataDialog(Variable variable) { VarDataDialogViewModel vm = new(); vm.Title = "编辑变量"; vm.PrimaryButtonText = "编辑变量"; - vm.VariableData = variableData; + vm.Variable = variable; var dialog = new VarDataDialog(vm); var res = await dialog.ShowAsync(); if (res == ContentDialogResult.Primary) { - return vm.VariableData; + return vm.Variable; } return null; } @@ -192,13 +192,13 @@ public class DialogService :IDialogService public async Task ShowMqttSelectionDialog() { - var vm = new MqttSelectionDialogViewModel(_mqttRepository); + var vm = new MqttSelectionDialogViewModel(_dataServices); var dialog = new MqttSelectionDialog(vm); var result = await dialog.ShowAsync(); return result == ContentDialogResult.Primary ? vm.SelectedMqtt : null; } - public async Task> ShowOpcUaImportDialog(string endpointUrl) + public async Task> ShowOpcUaImportDialog(string endpointUrl) { var vm= new OpcUaImportDialogViewModel(); vm.EndpointUrl = endpointUrl; @@ -250,7 +250,7 @@ public class DialogService :IDialogService return null; } - public async Task> ShowMqttAliasBatchEditDialog(List selectedVariables, Mqtt selectedMqtt) + public async Task> ShowMqttAliasBatchEditDialog(List selectedVariables, Mqtt selectedMqtt) { var vm = new MqttAliasBatchEditDialogViewModel(selectedVariables, selectedMqtt); var dialog = new MqttAliasBatchEditDialog(vm); diff --git a/Services/IDataProcessingService.cs b/Services/IDataProcessingService.cs index 2ba1133..632cb78 100644 --- a/Services/IDataProcessingService.cs +++ b/Services/IDataProcessingService.cs @@ -13,12 +13,12 @@ public interface IDataProcessingService /// 向处理链中添加一个数据处理器。 /// /// 要添加的数据处理器实例。 - void AddProcessor(IVariableDataProcessor processor); + void AddProcessor(IVariableProcessor processor); /// /// 将一个变量数据项异步推入处理队列。 /// /// 要入队的变量数据。 /// 一个表示入队操作的 ValueTask。 - ValueTask EnqueueAsync(VariableData data); + ValueTask EnqueueAsync(Variable data); } diff --git a/Services/IDialogService.cs b/Services/IDialogService.cs index 424f689..5229abd 100644 --- a/Services/IDialogService.cs +++ b/Services/IDialogService.cs @@ -15,18 +15,18 @@ public interface IDialogService Task ShowAddVarTableDialog(); Task ShowEditVarTableDialog(VariableTable variableTable); - Task ShowAddVarDataDialog(); + Task ShowAddVarDataDialog(); void ShowMessageDialog(string title, string message); - Task ShowEditVarDataDialog(VariableData variableData); + Task ShowEditVarDataDialog(Variable variable); Task ShowImportExcelDialog(); ContentDialog ShowProcessingDialog(string title, string message); Task ShowPollLevelDialog(PollLevelType pollLevelType); Task ShowMqttSelectionDialog(); - Task> ShowOpcUaImportDialog(string endpointUrl); + Task> ShowOpcUaImportDialog(string endpointUrl); Task ShowOpcUaUpdateTypeDialog(); Task ShowIsActiveDialog(bool currentIsActive); Task ShowImportResultDialog(List importedVariables, List existingVariables); Task ShowMqttAliasDialog(string variableName, string mqttServerName); - Task> ShowMqttAliasBatchEditDialog(List selectedVariables, Mqtt selectedMqtt); + Task> ShowMqttAliasBatchEditDialog(List selectedVariables, Mqtt selectedMqtt); } \ No newline at end of file diff --git a/Services/IVariableDataProcessor.cs b/Services/IVariableProcessor.cs similarity index 82% rename from Services/IVariableDataProcessor.cs rename to Services/IVariableProcessor.cs index d47ebfd..7db17f3 100644 --- a/Services/IVariableDataProcessor.cs +++ b/Services/IVariableProcessor.cs @@ -7,12 +7,12 @@ namespace PMSWPF.Services; /// 定义了变量数据处理器的通用接口。 /// 任何需要加入数据处理链的类都必须实现此接口。 /// -public interface IVariableDataProcessor +public interface IVariableProcessor { /// /// 异步处理单个变量数据。 /// /// 要处理的变量数据。 /// 一个表示异步操作的任务。 - Task ProcessAsync(VariableDataContext context); + Task ProcessAsync(VariableContext context); } diff --git a/Services/OpcUaBackgroundService.cs b/Services/OpcUaBackgroundService.cs index 623371b..12c019d 100644 --- a/Services/OpcUaBackgroundService.cs +++ b/Services/OpcUaBackgroundService.cs @@ -23,13 +23,13 @@ namespace PMSWPF.Services private readonly ConcurrentDictionary _opcUaSubscriptions; // 存储活动的 OPC UA 变量,键为变量的OpcNodeId - private readonly ConcurrentDictionary _opcUaPollVariablesByNodeId; + private readonly ConcurrentDictionary _opcUaPollVariablesByNodeId; // 储存所有要轮询更新的变量,键是Device.Id,值是这个设备所有要轮询的变量 - private readonly ConcurrentDictionary> _opcUaPollVariablesByDeviceId; + private readonly ConcurrentDictionary> _opcUaPollVariablesByDeviceId; // 储存所有要订阅更新的变量,键是Device.Id,值是这个设备所有要轮询的变量 - private readonly ConcurrentDictionary> _opcUaSubVariablesByDeviceId; + private readonly ConcurrentDictionary> _opcUaSubVariablesByDeviceId; private readonly SemaphoreSlim _reloadSemaphore = new SemaphoreSlim(0); @@ -49,9 +49,9 @@ namespace PMSWPF.Services _opcUaDevices = new ConcurrentDictionary(); _opcUaSessions = new ConcurrentDictionary(); _opcUaSubscriptions = new ConcurrentDictionary(); - _opcUaPollVariablesByNodeId = new ConcurrentDictionary(); - _opcUaPollVariablesByDeviceId = new ConcurrentDictionary>(); - _opcUaSubVariablesByDeviceId = new ConcurrentDictionary>(); + _opcUaPollVariablesByNodeId = new ConcurrentDictionary(); + _opcUaPollVariablesByDeviceId = new ConcurrentDictionary>(); + _opcUaSubVariablesByDeviceId = new ConcurrentDictionary>(); _dataServices.OnDeviceListChanged += HandleDeviceListChanged; _dataServices.OnDeviceIsActiveChanged += HandleDeviceIsActiveChanged; @@ -189,23 +189,23 @@ namespace PMSWPF.Services _opcUaDevices.AddOrUpdate(opcUaDevice.Id, opcUaDevice, (key, oldValue) => opcUaDevice); //查找设备中所有要轮询的变量 - var dPollList = opcUaDevice.VariableTables?.SelectMany(vt => vt.DataVariables) + var dPollList = opcUaDevice.VariableTables?.SelectMany(vt => vt.Variables) .Where(vd => vd.IsActive == true && vd.ProtocolType == ProtocolType.OpcUA && vd.OpcUaUpdateType == OpcUaUpdateType.OpcUaPoll) .ToList(); // 将变量保存到字典中,方便Read后还原 - foreach (var variableData in dPollList) + foreach (var variable in dPollList) { - _opcUaPollVariablesByNodeId.AddOrUpdate(variableData.OpcUaNodeId, variableData, - (key, oldValue) => variableData); + _opcUaPollVariablesByNodeId.AddOrUpdate(variable.OpcUaNodeId, variable, + (key, oldValue) => variable); } totalPollVariableCount += dPollList.Count; _opcUaPollVariablesByDeviceId.AddOrUpdate(opcUaDevice.Id, dPollList, (key, oldValue) => dPollList); //查找设备中所有要订阅的变量 - var dSubList = opcUaDevice.VariableTables?.SelectMany(vt => vt.DataVariables) + var dSubList = opcUaDevice.VariableTables?.SelectMany(vt => vt.Variables) .Where(vd => vd.IsActive == true && vd.ProtocolType == ProtocolType.OpcUA && vd.OpcUaUpdateType == OpcUaUpdateType.OpcUaSubscription) @@ -364,7 +364,7 @@ namespace PMSWPF.Services /// OPC UA 会话。 /// 要读取的变量。 /// 取消令牌。 - private async Task ReadAndProcessOpcUaVariableAsync(Session session, VariableData variable, CancellationToken stoppingToken) + private async Task ReadAndProcessOpcUaVariableAsync(Session session, Variable variable, CancellationToken stoppingToken) { var nodesToRead = new ReadValueIdCollection { @@ -387,7 +387,7 @@ namespace PMSWPF.Services return; } - await UpdateAndEnqueueVariableData(variable, result.Value); + await UpdateAndEnqueueVariable(variable, result.Value); } catch (ServiceResultException ex) when (ex.StatusCode == StatusCodes.BadSessionIdInvalid) { @@ -409,7 +409,7 @@ namespace PMSWPF.Services /// /// 要更新的变量。 /// 读取到的数据值。 - private async Task UpdateAndEnqueueVariableData(VariableData variable, object value) + private async Task UpdateAndEnqueueVariable(Variable variable, object value) { try { @@ -482,7 +482,7 @@ namespace PMSWPF.Services // 将变量添加到订阅 if (_opcUaSubVariablesByDeviceId.TryGetValue(deviceId, out var variablesToSubscribe)) { - foreach (VariableData variable in variablesToSubscribe) + foreach (Variable variable in variablesToSubscribe) { // 7. 创建监控项并添加到订阅中。 MonitoredItem monitoredItem = new MonitoredItem(subscription.DefaultItem); @@ -513,7 +513,7 @@ namespace PMSWPF.Services /// 发生变化的变量。 /// /// - private async void OnSubNotification(VariableData variable, MonitoredItem monitoredItem, + private async void OnSubNotification(Variable variable, MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e) { @@ -523,7 +523,7 @@ namespace PMSWPF.Services $"[OPC UA 通知] {monitoredItem.DisplayName}: {value.Value} | 时间戳: {value.SourceTimestamp.ToLocalTime()} | 状态: {value.StatusCode}"); if (StatusCode.IsGood(value.StatusCode)) { - await UpdateAndEnqueueVariableData(variable, value.Value); + await UpdateAndEnqueueVariable(variable, value.Value); } } } diff --git a/Services/Processors/CheckValueChangedProcessor.cs b/Services/Processors/CheckValueChangedProcessor.cs index f2f9192..f9cf952 100644 --- a/Services/Processors/CheckValueChangedProcessor.cs +++ b/Services/Processors/CheckValueChangedProcessor.cs @@ -3,7 +3,7 @@ using PMSWPF.Models; namespace PMSWPF.Services.Processors; -public class CheckValueChangedProcessor : IVariableDataProcessor +public class CheckValueChangedProcessor : IVariableProcessor { private readonly DataServices _dataServices; @@ -11,10 +11,10 @@ public class CheckValueChangedProcessor : IVariableDataProcessor { _dataServices = dataServices; } - public Task ProcessAsync(VariableDataContext context) + public Task ProcessAsync(VariableContext context) { - VariableData newVariable = context.Data; - if (!_dataServices.AllVariables.TryGetValue(newVariable.Id, out VariableData oldVariable)) + Variable newVariable = context.Data; + if (!_dataServices.AllVariables.TryGetValue(newVariable.Id, out Variable oldVariable)) { NlogHelper.Warn($"检查变量值是否改变时在_dataServices.AllVariables中找不到Id:{newVariable.Id},Name:{newVariable.Name}的变量。"); context.IsHandled = true; diff --git a/Services/Processors/HistoryDataProcessor.cs b/Services/Processors/HistoryProcessor.cs similarity index 84% rename from Services/Processors/HistoryDataProcessor.cs rename to Services/Processors/HistoryProcessor.cs index 7dd48c5..18e69e5 100644 --- a/Services/Processors/HistoryDataProcessor.cs +++ b/Services/Processors/HistoryProcessor.cs @@ -13,22 +13,22 @@ using PMSWPF.Services; namespace PMSWPF.Services.Processors; -public class HistoryDataProcessor : IVariableDataProcessor, IDisposable +public class HistoryProcessor : IVariableProcessor, IDisposable { private const int BATCH_SIZE = 50; // 批量写入的阈值 private const int TIMER_INTERVAL_MS = 30 * 1000; // 30秒 - private readonly ConcurrentQueue _queue = new(); + private readonly ConcurrentQueue _queue = new(); private readonly Timer _timer; - public HistoryDataProcessor() + public HistoryProcessor() { _timer = new Timer(async _ => await FlushQueueToDatabase(), null, Timeout.Infinite, Timeout.Infinite); _timer.Change(TIMER_INTERVAL_MS, TIMER_INTERVAL_MS); // 启动定时器 } - public async Task ProcessAsync(VariableDataContext context) + public async Task ProcessAsync(VariableContext context) { // 只有当数据发生变化时才记录历史 if (!context.Data.IsSave) // 如果数据已经被其他处理器处理过或者不需要保存,则跳过 @@ -36,13 +36,13 @@ public class HistoryDataProcessor : IVariableDataProcessor, IDisposable return; } - // 将 VariableData 转换为 DbVariableDataHistory - var historyData = new DbVariableDataHistory + // 将 Variable 转换为 DbVariableHistory + var historyData = new DbVariableHistory { Name = context.Data.Name, NodeId = context.Data.NodeId, DataValue = context.Data.DataValue, - VariableDataId = context.Data.Id, + VariableId = context.Data.Id, Timestamp = DateTime.Now // 记录当前时间 }; @@ -59,7 +59,7 @@ public class HistoryDataProcessor : IVariableDataProcessor, IDisposable // 停止定时器,防止在写入过程中再次触发 _timer.Change(Timeout.Infinite, Timeout.Infinite); - var itemsToProcess = new List(); + var itemsToProcess = new List(); while (_queue.TryDequeue(out var item)) { itemsToProcess.Add(item); diff --git a/Services/Processors/LoggingDataProcessor.cs b/Services/Processors/LoggingProcessor.cs similarity index 60% rename from Services/Processors/LoggingDataProcessor.cs rename to Services/Processors/LoggingProcessor.cs index f8c26d3..8747110 100644 --- a/Services/Processors/LoggingDataProcessor.cs +++ b/Services/Processors/LoggingProcessor.cs @@ -9,15 +9,15 @@ namespace PMSWPF.Services.Processors; /// 一个简单的数据处理器实现,用于演示。 /// 其主要功能是记录接收到的变量数据的名称和值。 /// -public class LoggingDataProcessor : IVariableDataProcessor +public class LoggingProcessor : IVariableProcessor { - public LoggingDataProcessor() + public LoggingProcessor() { } - public Task ProcessAsync(VariableDataContext context) + public Task ProcessAsync(VariableContext context) { - NlogHelper.Info($"处理数据: {context.Data.Name}, 值: {context.Data.DataValue}"); + // NlogHelper.Info($"处理数据: {context.Data.Name}, 值: {context.Data.DataValue}"); return Task.CompletedTask; } } diff --git a/Services/Processors/UpdateDbVariableProcessor.cs b/Services/Processors/UpdateDbVariableProcessor.cs index b962cd6..443065f 100644 --- a/Services/Processors/UpdateDbVariableProcessor.cs +++ b/Services/Processors/UpdateDbVariableProcessor.cs @@ -4,7 +4,7 @@ using PMSWPF.Helper; namespace PMSWPF.Services.Processors { - public class UpdateDbVariableProcessor : IVariableDataProcessor + public class UpdateDbVariableProcessor : IVariableProcessor { private readonly DataServices _dataServices; @@ -13,15 +13,15 @@ namespace PMSWPF.Services.Processors _dataServices = dataServices; } - public async Task ProcessAsync(VariableDataContext context) + public async Task ProcessAsync(VariableContext context) { try { - // 假设 DataServices 有一个方法来更新 VariableData - await _dataServices.UpdateVariableDataAsync(context.Data); - NlogHelper.Info($"数据库变量 {context.Data.Name} 更新成功,值为: {context.Data.DataValue}"); + // 假设 DataServices 有一个方法来更新 Variable + await _dataServices.UpdateVariableAsync(context.Data); + // NlogHelper.Info($"数据库变量 {context.Data.Name} 更新成功,值为: {context.Data.DataValue}"); - if (!_dataServices.AllVariables.TryGetValue(context.Data.Id, out VariableData oldVariable)) + if (!_dataServices.AllVariables.TryGetValue(context.Data.Id, out Variable oldVariable)) { NlogHelper.Warn($"数据库更新完成修改变量值是否改变时在_dataServices.AllVariables中找不到Id:{context.Data.Id},Name:{context.Data.Name}的变量。"); context.IsHandled = true; diff --git a/Services/S7BackgroundService.cs b/Services/S7BackgroundService.cs index c74942b..1c453aa 100644 --- a/Services/S7BackgroundService.cs +++ b/Services/S7BackgroundService.cs @@ -24,13 +24,13 @@ namespace PMSWPF.Services private readonly ConcurrentDictionary _s7Devices; // 储存所有要轮询更新的变量,键是Device.Id,值是这个设备所有要轮询的变量 - private readonly ConcurrentDictionary> _s7PollVariablesByDeviceId; // Key: VariableData.Id + private readonly ConcurrentDictionary> _s7PollVariablesByDeviceId; // Key: Variable.Id // 存储S7 PLC客户端实例的字典,键为设备ID,值为Plc对象。 private readonly ConcurrentDictionary _s7PlcClientsByIp; // 储存所有变量的字典,方便通过id获取变量对象 - private readonly Dictionary _s7VariablesById; + private readonly Dictionary _s7VariablesById; // S7轮询一次读取的变量数,不得大于15 private readonly int _s7PollOnceReadMultipleVars = 9; @@ -53,7 +53,7 @@ namespace PMSWPF.Services _dataServices = dataServices; _dataProcessingService = dataProcessingService; _s7Devices = new ConcurrentDictionary(); - _s7PollVariablesByDeviceId = new ConcurrentDictionary>(); + _s7PollVariablesByDeviceId = new ConcurrentDictionary>(); _s7PlcClientsByIp = new ConcurrentDictionary(); _s7VariablesById = new(); @@ -203,8 +203,8 @@ namespace PMSWPF.Services } // 轮询当前设备的所有变量 - var dataItemsToRead = new Dictionary(); // Key: VariableData.Id, Value: DataItem - var variablesToProcess = new List(); // List of variables to process in this batch + var dataItemsToRead = new Dictionary(); // Key: Variable.Id, Value: DataItem + var variablesToProcess = new List(); // List of variables to process in this batch foreach (var variable in variableList) { @@ -242,7 +242,7 @@ namespace PMSWPF.Services if (dataItemsToRead.TryGetValue(varData.Id, out var dataItem)) { // Now dataItem has the updated value from the PLC - await UpdateAndEnqueueVariableData(varData, dataItem); + await UpdateAndEnqueueVariable(varData, dataItem); } } } @@ -277,7 +277,7 @@ namespace PMSWPF.Services /// /// 要更新的变量。 /// 包含读取到的数据项。 - private async Task UpdateAndEnqueueVariableData(VariableData variable, DataItem dataItem) + private async Task UpdateAndEnqueueVariable(Variable variable, DataItem dataItem) { try { @@ -380,8 +380,8 @@ namespace PMSWPF.Services // 过滤出当前设备和S7协议相关的变量。 var deviceS7Variables = device.VariableTables - .Where(vt => vt.ProtocolType == ProtocolType.S7 && vt.IsActive) - .SelectMany(vt => vt.DataVariables) + .Where(vt => vt.ProtocolType == ProtocolType.S7 && vt.IsActive && vt.Variables != null) + .SelectMany(vt => vt.Variables) .Where(vd => vd.IsActive == true) .ToList(); // 转换为列表,避免多次枚举 @@ -393,6 +393,11 @@ namespace PMSWPF.Services _s7PollVariablesByDeviceId.AddOrUpdate(device.Id, deviceS7Variables, (key, oldValue) => deviceS7Variables); } + if (totalVariableCount==0) + { + return false; + } + NlogHelper.Info($"S7变量加载成功,共加载S7设备:{s7Devices.Count}个,变量数:{totalVariableCount}"); return true; } diff --git a/ViewModels/Dialogs/ImportExcelDialogViewModel.cs b/ViewModels/Dialogs/ImportExcelDialogViewModel.cs index 0b11734..27ee7a1 100644 --- a/ViewModels/Dialogs/ImportExcelDialogViewModel.cs +++ b/ViewModels/Dialogs/ImportExcelDialogViewModel.cs @@ -11,7 +11,7 @@ public partial class ImportExcelDialogViewModel : ObservableObject private string? _filePath; [ObservableProperty] - private ObservableCollection _variableData = new(); + private ObservableCollection _variables = new(); partial void OnFilePathChanged(string? value) { @@ -23,7 +23,7 @@ public partial class ImportExcelDialogViewModel : ObservableObject try { var data = ExcelHelper.ImprotFromTiaVariableTable(value); - VariableData = new ObservableCollection(data); + Variables = new ObservableCollection(data); } catch (System.Exception ex) { diff --git a/ViewModels/Dialogs/MqttAliasBatchEditDialogViewModel.cs b/ViewModels/Dialogs/MqttAliasBatchEditDialogViewModel.cs index 30ca763..c2aa9e4 100644 --- a/ViewModels/Dialogs/MqttAliasBatchEditDialogViewModel.cs +++ b/ViewModels/Dialogs/MqttAliasBatchEditDialogViewModel.cs @@ -17,7 +17,7 @@ public partial class MqttAliasBatchEditDialogViewModel : ObservableObject public Mqtt SelectedMqtt { get; private set; } - public MqttAliasBatchEditDialogViewModel(List selectedVariables, Mqtt selectedMqtt) + public MqttAliasBatchEditDialogViewModel(List selectedVariables, Mqtt selectedMqtt) { SelectedMqtt = selectedMqtt; Title=$"设置:{SelectedMqtt.Name}-MQTT服务器关联变量的别名"; diff --git a/ViewModels/Dialogs/MqttSelectionDialogViewModel.cs b/ViewModels/Dialogs/MqttSelectionDialogViewModel.cs index 469455b..cf8119c 100644 --- a/ViewModels/Dialogs/MqttSelectionDialogViewModel.cs +++ b/ViewModels/Dialogs/MqttSelectionDialogViewModel.cs @@ -3,12 +3,12 @@ using CommunityToolkit.Mvvm.ComponentModel; using PMSWPF.Models; using PMSWPF.Data.Repositories; using System.Threading.Tasks; +using PMSWPF.Services; namespace PMSWPF.ViewModels.Dialogs; public partial class MqttSelectionDialogViewModel : ObservableObject { - private readonly MqttRepository _mqttRepository; [ObservableProperty] private ObservableCollection mqtts; @@ -16,26 +16,10 @@ public partial class MqttSelectionDialogViewModel : ObservableObject [ObservableProperty] private Mqtt? selectedMqtt; - public MqttSelectionDialogViewModel(MqttRepository mqttRepository) + public MqttSelectionDialogViewModel(DataServices dataServices) { - _mqttRepository = mqttRepository; - LoadMqtts(); + Mqtts = new ObservableCollection(dataServices.Mqtts); } - private async void LoadMqtts() - { - try - { - var allMqtts = await _mqttRepository.GetAllAsync(); - Mqtts = new ObservableCollection(allMqtts); - } - catch (Exception ex) - { - // 这里需要一个日志记录器,但由于ViewModel中没有直接注入ILogger, - // 暂时使用Console.WriteLine或NotificationHelper - // 更好的做法是注入ILogger或使用静态日志类 - Console.WriteLine($"加载MQTT服务器列表失败: {ex.Message}"); - // 或者使用NotificationHelper.ShowMessage("加载MQTT服务器列表失败", NotificationType.Error); - } - } + } \ No newline at end of file diff --git a/ViewModels/Dialogs/OpcUaImportDialogViewModel.cs b/ViewModels/Dialogs/OpcUaImportDialogViewModel.cs index d7cd110..e7b35fe 100644 --- a/ViewModels/Dialogs/OpcUaImportDialogViewModel.cs +++ b/ViewModels/Dialogs/OpcUaImportDialogViewModel.cs @@ -21,9 +21,9 @@ public partial class OpcUaImportDialogViewModel : ObservableObject private ObservableCollection _opcUaNodes; [ObservableProperty] - private ObservableCollection _selectedNodeVariables; + private ObservableCollection _selectedNodeVariables; - public List SelectedVariables { get; set; }=new List(); + public List SelectedVariables { get; set; }=new List(); [ObservableProperty] private bool _selectAllVariables; @@ -36,7 +36,7 @@ public partial class OpcUaImportDialogViewModel : ObservableObject public OpcUaImportDialogViewModel() { OpcUaNodes = new ObservableCollection(); - SelectedNodeVariables = new ObservableCollection(); + SelectedNodeVariables = new ObservableCollection(); // Automatically connect when the ViewModel is created ConnectCommand.Execute(null); @@ -141,7 +141,7 @@ public partial class OpcUaImportDialogViewModel : ObservableObject { // 如果是变量节点,直接显示它 SelectedNodeVariables.Clear(); - SelectedNodeVariables.Add(new VariableData + SelectedNodeVariables.Add(new Variable { Name = node.DisplayName, NodeId = node.NodeId.ToString(), @@ -230,7 +230,7 @@ public partial class OpcUaImportDialogViewModel : ObservableObject dataType = _session.NodeCache.GetDisplayText(dataTypeNodeId); } - SelectedNodeVariables.Add(new VariableData + SelectedNodeVariables.Add(new Variable { Name = opcUaNode.DisplayName, OpcUaNodeId = opcUaNode.NodeId.ToString(), @@ -254,8 +254,8 @@ public partial class OpcUaImportDialogViewModel : ObservableObject } } - public ObservableCollection GetSelectedVariables() + public ObservableCollection GetSelectedVariables() { - return new ObservableCollection(SelectedVariables); + return new ObservableCollection(SelectedVariables); } } \ No newline at end of file diff --git a/ViewModels/Dialogs/VarDataDialogViewModel.cs b/ViewModels/Dialogs/VarDataDialogViewModel.cs index 977b855..27cb8cd 100644 --- a/ViewModels/Dialogs/VarDataDialogViewModel.cs +++ b/ViewModels/Dialogs/VarDataDialogViewModel.cs @@ -6,7 +6,7 @@ namespace PMSWPF.ViewModels.Dialogs; public partial class VarDataDialogViewModel : ObservableObject { [ObservableProperty] - private VariableData variableData; + private Variable _variable; [ObservableProperty] private string title; [ObservableProperty] diff --git a/ViewModels/MqttServerDetailViewModel.cs b/ViewModels/MqttServerDetailViewModel.cs index 2ca2d5f..1b0b329 100644 --- a/ViewModels/MqttServerDetailViewModel.cs +++ b/ViewModels/MqttServerDetailViewModel.cs @@ -81,7 +81,7 @@ namespace PMSWPF.ViewModels // 示例:假设变量数据也需要保存 // foreach (var variable in AssociatedVariables.Where(v => v.IsModified)) // { - // await _dataServices.UpdateVariableDataAsync(variable); + // await _dataServices.UpdateVariableAsync(variable); // } NotificationHelper.ShowInfo("MQTT服务器详情保存功能待实现。"); @@ -101,7 +101,7 @@ namespace PMSWPF.ViewModels return; } - var variablesList = variablesToRemove.Cast() + var variablesList = variablesToRemove.Cast() .ToList(); var result = await _dialogService.ShowConfrimeDialog( @@ -138,7 +138,7 @@ namespace PMSWPF.ViewModels _logger.LogInformation("AddAsync variables to MQTT server initiated."); // 假设我们已经通过对话框获取到了一些要添加的变量 - // List newVariables = ...; + // List newVariables = ...; // foreach (var variable in newVariables) // { // if (variable.Mqtts == null) variable.Mqtts = new List(); diff --git a/ViewModels/VariableTableViewModel.cs b/ViewModels/VariableTableViewModel.cs index 7471436..9c7bab2 100644 --- a/ViewModels/VariableTableViewModel.cs +++ b/ViewModels/VariableTableViewModel.cs @@ -26,12 +26,12 @@ namespace PMSWPF.ViewModels; /// 构造函数 负责初始化必要的服务和数据仓库。 /// 2. **数据加载**: /// - 当视图加载完成时,框架会自动调用 方法。 -/// - 此方法会根据传入的 对象初始化 集合,并设置协议类型相关的布尔属性。 -/// - 它还会创建 的深拷贝,用于在用户取消保存时还原数据。 +/// - 此方法会根据传入的 对象初始化 集合,并设置协议类型相关的布尔属性。 +/// - 它还会创建 的深拷贝,用于在用户取消保存时还原数据。 /// 3. **数据绑定与显示**: /// - 属性绑定到视图中显示的当前变量表信息。 -/// - 属性(ObservableCollection)绑定到视图中的数据网格或列表,用于显示变量数据。 -/// - 是一个 ICollectionView,用于支持数据过滤(通过 方法)和排序。 +/// - 属性(ObservableCollection)绑定到视图中的数据网格或列表,用于显示变量数据。 +/// - 是一个 ICollectionView,用于支持数据过滤(通过 方法)和排序。 /// - 属性绑定到搜索框,当其值改变时,会自动触发 方法刷新视图。 /// 4. **用户交互与命令**: /// - 视图中的按钮和其他交互元素通过 `RelayCommand` 绑定到 ViewModel 中的命令方法。 @@ -67,17 +67,17 @@ partial class VariableTableViewModel : ViewModelBase /// /// 存储当前变量表中的所有变量数据的集合。 - /// 通过 ObservableProperty 自动生成 DataVariables 属性和 OnDataVariablesChanged 方法。 + /// 通过 ObservableProperty 自动生成 Variables 属性和 OnVariablesChanged 方法。 /// [ObservableProperty] - private ObservableCollection _dataVariables; + private ObservableCollection _variables; /// /// 当前选中的变量数据。 - /// 通过 ObservableProperty 自动生成 SelectedVariableData 属性和 OnSelectedVariableDataChanged 方法。 + /// 通过 ObservableProperty 自动生成 SelectedVariable 属性和 OnSelectedVariableDataChanged 方法。 /// [ObservableProperty] - private VariableData _selectedVariableData; + private Variable _selectedVariable; /// /// 用于过滤变量数据的搜索文本。 @@ -90,7 +90,7 @@ partial class VariableTableViewModel : ViewModelBase /// 用于在UI中显示和过滤变量数据的视图集合。 /// [ObservableProperty] - private ICollectionView variableDataView; + private ICollectionView variableView; /// /// 指示视图是否已完成首次加载。 @@ -111,7 +111,7 @@ partial class VariableTableViewModel : ViewModelBase /// /// 原始变量数据的深拷贝备份,用于在用户取消保存时还原数据。 /// - private ObservableCollection? _originalDataVariables; + private ObservableCollection? _originalVariables; /// /// 指示当前变量表是否使用S7协议。 @@ -143,13 +143,13 @@ partial class VariableTableViewModel : ViewModelBase IsLoadCompletion = false; // 初始设置为 false,表示未完成加载 _varTableRepository = varTableRepository; _varDataRepository = varDataRepository; - _dataVariables = new ObservableCollection(); // 初始化集合 - VariableDataView = CollectionViewSource.GetDefaultView(DataVariables); // 获取集合视图 - VariableDataView.Filter = FilterVariables; // 设置过滤方法 + _variables = new ObservableCollection(); // 初始化集合 + VariableView = CollectionViewSource.GetDefaultView(Variables); // 获取集合视图 + VariableView.Filter = FilterVariables; // 设置过滤方法 } /// - /// 用于过滤 中的变量数据。 + /// 用于过滤 中的变量数据。 /// 根据 属性的值进行模糊匹配。 /// /// 要过滤的集合中的单个项。 @@ -162,8 +162,8 @@ partial class VariableTableViewModel : ViewModelBase return true; } - // 尝试将项转换为 VariableData 类型 - if (item is VariableData variable) + // 尝试将项转换为 Variable 类型 + if (item is Variable variable) { var searchTextLower = SearchText.ToLower(); // 检查变量的名称、描述、NodeId、S7地址、数据值或显示值是否包含搜索文本 @@ -186,12 +186,12 @@ partial class VariableTableViewModel : ViewModelBase /// /// 当 属性的值发生改变时自动调用。 - /// 刷新 以应用新的过滤条件。 + /// 刷新 以应用新的过滤条件。 /// /// 新的搜索文本值。 partial void OnSearchTextChanged(string value) { - VariableDataView?.Refresh(); + VariableView?.Refresh(); } /// @@ -205,26 +205,30 @@ partial class VariableTableViewModel : ViewModelBase IsOpcUaProtocolSelected = VariableTable.ProtocolType == ProtocolType.OpcUA; // 如果变量表包含数据变量,则进行初始化 - if (VariableTable.DataVariables != null) + if (VariableTable.Variables != null) { // // 将变量表中的数据变量复制到可观察集合中 - DataVariables.Clear(); // 清空现有集合 - foreach (var item in VariableTable.DataVariables) + Variables.Clear(); // 清空现有集合 + foreach (var item in VariableTable.Variables) { - DataVariables.Add(item); // 添加新项 + Variables.Add(item); // 添加新项 } - VariableDataView.Refresh(); // 刷新视图以应用过滤和排序 + VariableView.Refresh(); // 刷新视图以应用过滤和排序 // 创建原始数据的深拷贝备份,用于在取消保存时还原 - var serialized = JsonConvert.SerializeObject(DataVariables); - _originalDataVariables = JsonConvert.DeserializeObject>(serialized); + var settings = new JsonSerializerSettings + { + ReferenceLoopHandling = ReferenceLoopHandling.Ignore + }; + var serialized = JsonConvert.SerializeObject(Variables, settings); + _originalVariables = JsonConvert.DeserializeObject>(serialized); // 在数据加载完成后,将所有变量的 IsModified 状态重置为 false - foreach (var variableData in DataVariables) + foreach (var variable in Variables) { - variableData.IsModified = false; + variable.IsModified = false; } } @@ -240,7 +244,7 @@ partial class VariableTableViewModel : ViewModelBase public override async Task OnExitAsync() { // 查找所有已修改的变量数据 - var modifiedDatas = DataVariables.Where(d => d.IsModified == true) + var modifiedDatas = Variables.Where(d => d.IsModified == true) .ToList(); // 如果没有修改,则直接允许退出 if (modifiedDatas.Count == 0) @@ -256,7 +260,7 @@ partial class VariableTableViewModel : ViewModelBase // 遍历所有已修改的数据,从原始备份中还原 foreach (var modifiedData in modifiedDatas) { - var oldData = _originalDataVariables.First(od => od.Id == modifiedData.Id); + var oldData = _originalVariables.First(od => od.Id == modifiedData.Id); // 将原始数据复制回当前数据 _mapper.Map(oldData, modifiedData); modifiedData.IsModified = false; // 重置修改状态 @@ -276,7 +280,7 @@ partial class VariableTableViewModel : ViewModelBase private async void SaveModifiedVarData() { // 查找所有已标记为修改的变量数据 - var modifiedDatas = DataVariables.Where(d => d.IsModified == true) + var modifiedDatas = Variables.Where(d => d.IsModified == true) .ToList(); // 更新数据库中的这些数据 await _varDataRepository.UpdateAsync(modifiedDatas); @@ -297,12 +301,12 @@ partial class VariableTableViewModel : ViewModelBase /// /// 当前操作的变量表,用于更新其内部的变量数据。 [RelayCommand] - private async void EditVarData(VariableTable variableTable) + private async void UpdateVariable(VariableTable variableTable) { try { // 显示编辑变量数据的对话框,并传入当前选中的变量数据 - var varData = await _dialogService.ShowEditVarDataDialog(SelectedVariableData); + var varData = await _dialogService.ShowEditVarDataDialog(SelectedVariable); // 如果用户取消或对话框未返回数据,则直接返回 if (varData == null) @@ -315,9 +319,9 @@ partial class VariableTableViewModel : ViewModelBase await _varDataRepository.UpdateAsync(varData); // 更新当前页面显示的数据:找到原数据在集合中的索引并替换 - var index = variableTable.DataVariables.IndexOf(SelectedVariableData); - if (index >= 0 && index < variableTable.DataVariables.Count) - variableTable.DataVariables[index] = varData; // 替换为编辑后的数据 + var index = variableTable.Variables.IndexOf(SelectedVariable); + if (index >= 0 && index < variableTable.Variables.Count) + variableTable.Variables[index] = varData; // 替换为编辑后的数据 // 显示成功通知 NotificationHelper.ShowSuccess($"编辑变量成功:{varData?.Name}"); @@ -344,7 +348,7 @@ partial class VariableTableViewModel : ViewModelBase if (string.IsNullOrEmpty(filePath)) return; // 如果用户取消选择,则返回 - // 读取Excel文件并将其内容转换为 VariableData 列表 + // 读取Excel文件并将其内容转换为 Variable 列表 var importVarDataList = ExcelHelper.ImprotFromTiaVariableTable(filePath); if (importVarDataList.Count == 0) return; // 如果没有读取到数据,则返回 @@ -352,15 +356,15 @@ partial class VariableTableViewModel : ViewModelBase // 显示处理中的对话框 processingDialog = _dialogService.ShowProcessingDialog("正在处理...", "正在导入变量,请稍等片刻...."); - List newVariables = new List(); + List newVariables = new List(); List importedVariableNames = new List(); List existingVariableNames = new List(); foreach (var variableData in importVarDataList) { // 判断是否存在重复变量 - // 判断是否存在重复变量,仅在当前 VariableTable 的 DataVariables 中查找 - bool isDuplicate = DataVariables.Any(existingVar => + // 判断是否存在重复变量,仅在当前 VariableTable 的 Variables 中查找 + bool isDuplicate = Variables.Any(existingVar => (existingVar.Name == variableData.Name) || (!string.IsNullOrEmpty(variableData.NodeId) && existingVar.NodeId == variableData.NodeId) || @@ -436,17 +440,17 @@ partial class VariableTableViewModel : ViewModelBase // 显示处理中的对话框 processingDialog = _dialogService.ShowProcessingDialog("正在处理...", "正在导入OPC UA变量,请稍等片刻...."); - // 在进行重复检查之前,先刷新 DataVariables 集合,确保其包含所有最新数据 + // 在进行重复检查之前,先刷新 Variables 集合,确保其包含所有最新数据 await RefreshDataView(); - List newVariables = new List(); + List newVariables = new List(); List importedVariableNames = new List(); List existingVariableNames = new List(); foreach (var variableData in importedVariables) { - // 判断是否存在重复变量,仅在当前 VariableTable 的 DataVariables 中查找 - bool isDuplicate = DataVariables.Any(existingVar => + // 判断是否存在重复变量,仅在当前 VariableTable 的 Variables 中查找 + bool isDuplicate = Variables.Any(existingVar => (existingVar.Name == variableData.Name) || (!string.IsNullOrEmpty(variableData.NodeId) && existingVar.NodeId == variableData.NodeId) || @@ -476,7 +480,7 @@ partial class VariableTableViewModel : ViewModelBase NlogHelper.Info($"成功导入OPC UA变量:{resVarDataCount}个。"); } - // 再次刷新 DataVariables 集合,以反映新添加的数据 + // 再次刷新 Variables 集合,以反映新添加的数据 await RefreshDataView(); processingDialog?.Hide(); // 隐藏处理中的对话框 @@ -506,13 +510,13 @@ partial class VariableTableViewModel : ViewModelBase // 将最新数据转换为字典,以便快速查找 var latestVariablesDict = latestVariables.ToDictionary(v => v.Id); - // 用于存储需要从 DataVariables 中移除的项 - var itemsToRemove = new List(); + // 用于存储需要从 Variables 中移除的项 + var itemsToRemove = new List(); - // 遍历当前 DataVariables 集合,处理删除和更新 - for (int i = DataVariables.Count - 1; i >= 0; i--) + // 遍历当前 Variables 集合,处理删除和更新 + for (int i = Variables.Count - 1; i >= 0; i--) { - var currentVariable = DataVariables[i]; + var currentVariable = Variables[i]; if (latestVariablesDict.TryGetValue(currentVariable.Id, out var newVariable)) { // 如果存在于最新数据中,检查是否需要更新 @@ -535,17 +539,17 @@ partial class VariableTableViewModel : ViewModelBase // 移除已标记的项 foreach (var item in itemsToRemove) { - DataVariables.Remove(item); + Variables.Remove(item); } // 添加所有剩余在 latestVariablesDict 中的项(这些是新增项) foreach (var newVariable in latestVariablesDict.Values) { - DataVariables.Add(newVariable); + Variables.Add(newVariable); } // 刷新视图以应用所有更改 - VariableDataView.Refresh(); + VariableView.Refresh(); } // @@ -574,7 +578,7 @@ partial class VariableTableViewModel : ViewModelBase string duplicateReason = string.Empty; // 检查名称是否重复 - if (DataVariables.Any(v => v.Name == varData.Name)) + if (Variables.Any(v => v.Name == varData.Name)) { isDuplicate = true; duplicateReason = $"名称 '{varData.Name}' 已存在。"; @@ -585,7 +589,7 @@ partial class VariableTableViewModel : ViewModelBase if (variableTable.ProtocolType == ProtocolType.S7) { if (!string.IsNullOrEmpty(varData.S7Address) && - DataVariables.Any(v => v.S7Address == varData.S7Address)) + Variables.Any(v => v.S7Address == varData.S7Address)) { isDuplicate = true; duplicateReason = $"S7地址 '{varData.S7Address}' 已存在。"; @@ -593,7 +597,7 @@ partial class VariableTableViewModel : ViewModelBase } else if (variableTable.ProtocolType == ProtocolType.OpcUA) { - if (!string.IsNullOrEmpty(varData.NodeId) && DataVariables.Any(v => v.NodeId == varData.NodeId)) + if (!string.IsNullOrEmpty(varData.NodeId) && Variables.Any(v => v.NodeId == varData.NodeId)) { isDuplicate = true; duplicateReason = $"OPC UA NodeId '{varData.NodeId}' 已存在。"; @@ -617,7 +621,7 @@ partial class VariableTableViewModel : ViewModelBase } // 更新当前页面显示的数据:将新变量添加到集合中 - DataVariables.Add(resVarData); + Variables.Add(resVarData); // 显示成功通知 NotificationHelper.ShowSuccess($"添加变量成功:{varData?.Name}"); @@ -635,7 +639,7 @@ partial class VariableTableViewModel : ViewModelBase /// /// 要删除的变量数据列表。 [RelayCommand] - public async Task DeleteVarData(List variablesToDelete) + public async Task DeleteVarData(List variablesToDelete) { // 检查是否有变量被选中 if (variablesToDelete == null || !variablesToDelete.Any()) @@ -687,7 +691,7 @@ partial class VariableTableViewModel : ViewModelBase [RelayCommand] public async Task ChangePollLevel(IList variablesToChange) { - var validVariables = variablesToChange?.OfType() + var validVariables = variablesToChange?.OfType() .ToList(); // 检查是否有变量被选中 @@ -711,6 +715,8 @@ partial class VariableTableViewModel : ViewModelBase // 批量更新数据库中的变量数据 await _varDataRepository.UpdateAsync(validVariables); + + await RefreshDataView(); // 显示成功通知 NotificationHelper.ShowSuccess($"已成功更新 {validVariables.Count} 个变量的轮询频率"); } @@ -724,7 +730,7 @@ partial class VariableTableViewModel : ViewModelBase public async Task ModifyOpcUaUpdateType(IList variablesToChange) { // 过滤出有效的VariableData对象 - var validVariables = variablesToChange?.OfType() + var validVariables = variablesToChange?.OfType() .ToList(); if (validVariables == null || !validVariables.Any()) @@ -758,7 +764,7 @@ partial class VariableTableViewModel : ViewModelBase [RelayCommand] public async Task AddMqttServerToVariables(IList variablesToAddMqtt) { - var validVariables = variablesToAddMqtt?.OfType() + var validVariables = variablesToAddMqtt?.OfType() .ToList(); // 检查是否有变量被选中 @@ -789,19 +795,22 @@ partial class VariableTableViewModel : ViewModelBase int totalAffectedCount = 0; // 调用仓库方法来添加或更新MQTT服务器关联和别名 - var affectedCount = await _varDataRepository.AddMqttToVariablesAsync(editedVariableMqtts); - totalAffectedCount += affectedCount; - if (affectedCount == 0) - { - NotificationHelper.ShowInfo("没有任何要添加或者更新的MQTT服务器."); - return; - } + var resCount = await _varDataRepository.AddMqttToVariablesAsync(editedVariableMqtts); + totalAffectedCount += resCount; + + //更新变量Variable的VariableMqtts列表 foreach (var editedVariableMqtt in editedVariableMqtts) { - - // 更新内存中的 VariableData 对象 - var originalVariable = editedVariableMqtt.VariableData; + // 更新内存中的 Variable 对象 + var originalVariable = VariableTable.Variables.FirstOrDefault(v=>v.Id==editedVariableMqtt.Variable.Id); + if (originalVariable == null) + { + NlogHelper.Warn($"没有在VariableTable.Variables中找到,ID:{editedVariableMqtt.Variable.Id},Name:{editedVariableMqtt.Variable.Name}的对象"); + continue; + } + + if (originalVariable.VariableMqtts == null) { originalVariable.VariableMqtts = new List(); @@ -815,13 +824,16 @@ partial class VariableTableViewModel : ViewModelBase if (existingVariableMqtt == null) { // 如果不存在,则添加新的关联 - originalVariable.VariableMqtts.Add(new VariableMqtt - { - VariableDataId = originalVariable.Id, - MqttId = editedVariableMqtt.Mqtt.Id, - MqttAlias = editedVariableMqtt.MqttAlias, - Mqtt = editedVariableMqtt.Mqtt // 关联Mqtt对象,方便UI显示 - }); + var variableMqtt = new VariableMqtt(originalVariable,editedVariableMqtt.Mqtt) + { + VariableId = originalVariable.Id, + MqttId = editedVariableMqtt.Mqtt.Id, + MqttAlias = editedVariableMqtt.MqttAlias, + Mqtt = editedVariableMqtt.Mqtt // 关联Mqtt对象,方便UI显示 + }; + originalVariable.VariableMqtts.Add(variableMqtt); + //更新MQTT服务器对应的的VariableMqtts列表 + selectedMqtt.VariableMqtts.Add(variableMqtt); } else { @@ -856,7 +868,7 @@ partial class VariableTableViewModel : ViewModelBase [RelayCommand] public async Task ModifyIsActive(IList variablesToChange) { - var validVariables = variablesToChange?.OfType() + var validVariables = variablesToChange?.OfType() .ToList(); if (validVariables == null || !validVariables.Any()) diff --git a/Views/Dialogs/ImportExcelDialog.xaml b/Views/Dialogs/ImportExcelDialog.xaml index b590a55..b644ba6 100644 --- a/Views/Dialogs/ImportExcelDialog.xaml +++ b/Views/Dialogs/ImportExcelDialog.xaml @@ -41,14 +41,14 @@