From 35e5033094c71064a136f91072e9413fa7c069d0 Mon Sep 17 00:00:00 2001 From: "David P.G" Date: Thu, 24 Jul 2025 21:41:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=8F=98=E9=87=8F=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E7=9A=84=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DMS.Application/DTOs/VariableDto.cs | 7 +- .../Interfaces/IVariableAppService.cs | 4 +- DMS.Application/Profiles/MappingProfile.cs | 15 +++- .../Services/VariableAppService.cs | 31 +++++--- DMS.Infrastructure.UnitTests/FakerHelper.cs | 26 +++++++ .../Services/BaseServiceTest.cs | 1 + .../Services/VariableAppServiceTest.cs | 78 +++++++++++++++++++ DMS.Infrastructure/Entities/DbVariable.cs | 9 ++- DMS.Infrastructure/Profiles/MappingProfile.cs | 1 - 9 files changed, 152 insertions(+), 20 deletions(-) create mode 100644 DMS.Infrastructure.UnitTests/Services/VariableAppServiceTest.cs diff --git a/DMS.Application/DTOs/VariableDto.cs b/DMS.Application/DTOs/VariableDto.cs index 19db443..fb7c8cd 100644 --- a/DMS.Application/DTOs/VariableDto.cs +++ b/DMS.Application/DTOs/VariableDto.cs @@ -10,7 +10,11 @@ public class VariableDto { public int Id { get; set; } public string Name { get; set; } - public string Address { get; set; } + public string? S7Address { get; set; } + public string? DataValue { get; set; } + public string? DisplayValue { get; set; } + public VariableTableDto? VariableTable { get; set; } + public List? MqttAliases { get; set; } public SignalType DataType { get; set; } public PollLevelType PollLevel { get; set; } public bool IsActive { get; set; } @@ -29,4 +33,5 @@ public class VariableDto public DateTime UpdatedAt { get; set; } public string UpdatedBy { get; set; } public bool IsModified { get; set; } + public string Description { get; set; } } \ No newline at end of file diff --git a/DMS.Application/Interfaces/IVariableAppService.cs b/DMS.Application/Interfaces/IVariableAppService.cs index a349eff..557b7dc 100644 --- a/DMS.Application/Interfaces/IVariableAppService.cs +++ b/DMS.Application/Interfaces/IVariableAppService.cs @@ -25,10 +25,10 @@ public interface IVariableAppService /// /// 异步更新一个已存在的变量。 /// - Task UpdateVariableAsync(VariableDto variableDto); + Task UpdateVariableAsync(VariableDto variableDto); /// /// 异步删除一个变量。 /// - Task DeleteVariableAsync(int id); + Task DeleteVariableAsync(int id); } \ No newline at end of file diff --git a/DMS.Application/Profiles/MappingProfile.cs b/DMS.Application/Profiles/MappingProfile.cs index 33f6963..0e4ee77 100644 --- a/DMS.Application/Profiles/MappingProfile.cs +++ b/DMS.Application/Profiles/MappingProfile.cs @@ -45,7 +45,20 @@ public class MappingProfile : Profile CreateMap() .ForMember(dest => dest.DataType, opt => opt.MapFrom(src => src.DataType.ToString())) .ForMember(dest => dest.CSharpDataType, opt => opt.MapFrom(src => src.CSharpDataType)) - .ForMember(dest => dest.Address, opt => opt.Ignore()); + .ForMember(dest => dest.S7Address, opt => opt.MapFrom(src => src.S7Address)) + .ForMember(dest => dest.DataValue, opt => opt.MapFrom(src => src.DataValue)) + .ForMember(dest => dest.DisplayValue, opt => opt.MapFrom(src => src.DisplayValue)) + .ForMember(dest => dest.VariableTable, opt => opt.MapFrom(src => src.VariableTable)) + .ForMember(dest => dest.MqttAliases, opt => opt.MapFrom(src => src.MqttAliases)) + .ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.Description)); + + CreateMap() + .ForMember(dest => dest.S7Address, opt => opt.MapFrom(src => src.S7Address)) + .ForMember(dest => dest.VariableTable, opt => opt.Ignore()) + .ForMember(dest => dest.MqttAliases, opt => opt.Ignore()) + .ForMember(dest => dest.DataValue, opt => opt.Ignore()) + .ForMember(dest => dest.DisplayValue, opt => opt.Ignore()) + .ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.Description)); // MqttServer 映射 CreateMap().ReverseMap(); diff --git a/DMS.Application/Services/VariableAppService.cs b/DMS.Application/Services/VariableAppService.cs index 6a7f7e9..4443e08 100644 --- a/DMS.Application/Services/VariableAppService.cs +++ b/DMS.Application/Services/VariableAppService.cs @@ -59,14 +59,14 @@ public class VariableAppService : IVariableAppService { await _repoManager.BeginTranAsync(); var variable = _mapper.Map(variableDto); - await _repoManager.Variables.AddAsync(variable); + var addedVariable = await _repoManager.Variables.AddAsync(variable); await _repoManager.CommitAsync(); - return variable.Id; + return addedVariable.Id; } catch (Exception ex) { await _repoManager.RollbackAsync(); - throw new ApplicationException("创建变量时发生错误,操作已回滚。", ex); + throw new ApplicationException($"创建变量时发生错误,操作已回滚,错误信息:{ex.Message}", ex); } } @@ -74,9 +74,9 @@ public class VariableAppService : IVariableAppService /// 异步更新一个已存在的变量(事务性操作)。 /// /// 要更新的变量数据传输对象。 - /// 表示异步操作的任务。 + /// 受影响的行数。 /// 如果找不到变量或更新变量时发生错误。 - public async Task UpdateVariableAsync(VariableDto variableDto) + public async Task UpdateVariableAsync(VariableDto variableDto) { try { @@ -87,13 +87,14 @@ public class VariableAppService : IVariableAppService throw new ApplicationException($"Variable with ID {variableDto.Id} not found."); } _mapper.Map(variableDto, variable); - await _repoManager.Variables.UpdateAsync(variable); + int res = await _repoManager.Variables.UpdateAsync(variable); await _repoManager.CommitAsync(); + return res; } catch (Exception ex) { await _repoManager.RollbackAsync(); - throw new ApplicationException("更新变量时发生错误,操作已回滚。", ex); + throw new ApplicationException($"更新变量时发生错误,操作已回滚,错误信息:{ex.Message}", ex); } } @@ -101,20 +102,26 @@ public class VariableAppService : IVariableAppService /// 异步删除一个变量(事务性操作)。 /// /// 要删除变量的ID。 - /// 表示异步操作的任务。 - /// 如果删除变量时发生错误。 - public async Task DeleteVariableAsync(int id) + /// 如果删除成功则为 true,否则为 false。 + /// 如果删除变量失败。 + /// 如果删除变量时发生其他错误。 + public async Task DeleteVariableAsync(int id) { try { await _repoManager.BeginTranAsync(); - await _repoManager.Variables.DeleteByIdAsync(id); + var delRes = await _repoManager.Variables.DeleteByIdAsync(id); + if (delRes == 0) + { + throw new InvalidOperationException($"删除变量失败:变量ID:{id},请检查变量Id是否存在"); + } await _repoManager.CommitAsync(); + return true; } catch (Exception ex) { await _repoManager.RollbackAsync(); - throw new ApplicationException("删除变量时发生错误,操作已回滚。", ex); + throw new ApplicationException($"删除变量时发生错误,操作已回滚,错误信息:{ex.Message}", ex); } } } \ No newline at end of file diff --git a/DMS.Infrastructure.UnitTests/FakerHelper.cs b/DMS.Infrastructure.UnitTests/FakerHelper.cs index 987d601..7da45c0 100644 --- a/DMS.Infrastructure.UnitTests/FakerHelper.cs +++ b/DMS.Infrastructure.UnitTests/FakerHelper.cs @@ -142,5 +142,31 @@ namespace DMS.Infrastructure.UnitTests return menuDto; } + public static VariableDto FakeVariableDto() + { + var variableDto = new Faker() + .RuleFor(v => v.Name, f => f.Commerce.ProductName()) + .RuleFor(v => v.S7Address, f => $"DB1.DBD{f.Random.Int(0, 1000)}") + .RuleFor(v => v.DataType, f => f.PickRandom()) + .RuleFor(v => v.PollLevel, f => f.PickRandom()) + .RuleFor(v => v.IsActive, f => f.Random.Bool()) + .RuleFor(v => v.IsHistoryEnabled, f => f.Random.Bool()) + .RuleFor(v => v.HistoryDeadband, f => f.Random.Double(0.0, 1.0)) + .RuleFor(v => v.IsAlarmEnabled, f => f.Random.Bool()) + .RuleFor(v => v.AlarmMinValue, f => f.Random.Double(0.0, 50.0)) + .RuleFor(v => v.AlarmMaxValue, f => f.Random.Double(50.0, 100.0)) + .RuleFor(v => v.AlarmDeadband, f => f.Random.Double(0.0, 1.0)) + .RuleFor(v => v.Protocol, f => f.PickRandom()) + .RuleFor(v => v.CSharpDataType, f => f.PickRandom(Enum.GetValues())) + .RuleFor(v => v.OpcUaNodeId, f => $"ns=2;s=My.Variable{f.Random.Int(1, 100)}") + .RuleFor(v => v.ConversionFormula, f => "x * 1.0") + .RuleFor(v => v.UpdatedBy, f => f.Name.FullName()) + .RuleFor(v => v.DataValue, f => f.Random.Double(0, 100).ToString()) + .RuleFor(v => v.DisplayValue, f => f.Random.Word()) + .RuleFor(v => v.Description, f => f.Lorem.Sentence()) + .Generate(); + variableDto.VariableTableId = 1; // Default to 1 for testing purposes + return variableDto; + } } } diff --git a/DMS.Infrastructure.UnitTests/Services/BaseServiceTest.cs b/DMS.Infrastructure.UnitTests/Services/BaseServiceTest.cs index 15abe4f..a67b5a8 100644 --- a/DMS.Infrastructure.UnitTests/Services/BaseServiceTest.cs +++ b/DMS.Infrastructure.UnitTests/Services/BaseServiceTest.cs @@ -51,6 +51,7 @@ public class BaseServiceTest // 注册应用服务 services.AddTransient(); services.AddTransient(); + services.AddTransient(); // services.AddTransient(); // 如果需要测试 VariableService,取消此行注释 // ... 在这里注册所有其他的应用服务 ... diff --git a/DMS.Infrastructure.UnitTests/Services/VariableAppServiceTest.cs b/DMS.Infrastructure.UnitTests/Services/VariableAppServiceTest.cs new file mode 100644 index 0000000..af5e7b7 --- /dev/null +++ b/DMS.Infrastructure.UnitTests/Services/VariableAppServiceTest.cs @@ -0,0 +1,78 @@ +using DMS.Application.DTOs; +using DMS.Application.Interfaces; +using DMS.Application.Services; +using JetBrains.Annotations; +using Microsoft.Extensions.DependencyInjection; + +namespace DMS.Infrastructure.UnitTests.Services; + +[TestSubject(typeof(VariableAppService))] +public class VariableAppServiceTest : BaseServiceTest +{ + private readonly IVariableAppService _variableAppService; + + public VariableAppServiceTest() + { + _variableAppService = ServiceProvider.GetRequiredService(); + } + + [Fact] + public async Task CreateVariableAsyncTest() + { + // Arrange + var dto = FakerHelper.FakeVariableDto(); + dto.VariableTableId = 1; // Assuming a variable table with ID 1 exists for testing + + // Act + var createdId = await _variableAppService.CreateVariableAsync(dto); + + // Assert + Assert.NotEqual(0, createdId); + } + + [Fact] + public async Task UpdateVariableAsyncTest() + { + // Arrange: Create a variable first + var createDto = FakerHelper.FakeVariableDto(); + createDto.VariableTableId = 1; // Assuming a variable table with ID 1 exists for testing + var createdId = await _variableAppService.CreateVariableAsync(createDto); + Assert.NotEqual(0, createdId); + + // Retrieve the created variable to update + var variableToUpdate = await _variableAppService.GetVariableByIdAsync(createdId); + Assert.NotNull(variableToUpdate); + + // Modify some properties + variableToUpdate.Name = "Updated Variable Name"; + variableToUpdate.Description = "Updated Description"; + + // Act + var affectedRows = await _variableAppService.UpdateVariableAsync(variableToUpdate); + + // Assert + Assert.Equal(1, affectedRows); + var updatedVariable = await _variableAppService.GetVariableByIdAsync(createdId); + Assert.NotNull(updatedVariable); + Assert.Equal("Updated Variable Name", updatedVariable.Name); + Assert.Equal("Updated Description", updatedVariable.Description); + } + + [Fact] + public async Task DeleteVariableAsyncTest() + { + // Arrange: Create a variable first + var createDto = FakerHelper.FakeVariableDto(); + createDto.VariableTableId = 1; // Assuming a variable table with ID 1 exists for testing + var createdId = await _variableAppService.CreateVariableAsync(createDto); + Assert.NotEqual(0, createdId); + + // Act + var isDeleted = await _variableAppService.DeleteVariableAsync(createdId); + + // Assert + Assert.True(isDeleted); + var deletedVariable = await _variableAppService.GetVariableByIdAsync(createdId); + Assert.Null(deletedVariable); + } +} \ No newline at end of file diff --git a/DMS.Infrastructure/Entities/DbVariable.cs b/DMS.Infrastructure/Entities/DbVariable.cs index b9dae05..c69834f 100644 --- a/DMS.Infrastructure/Entities/DbVariable.cs +++ b/DMS.Infrastructure/Entities/DbVariable.cs @@ -1,4 +1,5 @@ using SqlSugar; +using SqlSugar.DbConvert; namespace DMS.Infrastructure.Entities; @@ -7,7 +8,7 @@ public class DbVariable [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] public int Id { get; set; } public string Name { get; set; } - public string Address { get; set; } + public string Description { get; set; } public int DataType { get; set; } // 对应 SignalType 枚举 public int PollLevel { get; set; } // 对应 PollLevelType 枚举 public bool IsActive { get; set; } @@ -20,8 +21,10 @@ public class DbVariable public double AlarmMinValue { get; set; } public double AlarmMaxValue { get; set; } public double AlarmDeadband { get; set; } - public int Protocol { get; set; } // 对应 ProtocolType 枚举 - public int CSharpDataType { get; set; } // 对应 CSharpDataType 枚举 + [SugarColumn(ColumnDataType="varchar(20)",SqlParameterDbType=typeof(EnumToStringConvert))] + public ProtocolType Protocol { get; set; } // 对应 ProtocolType 枚举 + [SugarColumn(ColumnDataType="varchar(20)",SqlParameterDbType=typeof(EnumToStringConvert))] + public CSharpDataType CSharpDataType { get; set; } // 对应 CSharpDataType 枚举 public string ConversionFormula { get; set; } public DateTime CreatedAt { get; set; } public DateTime UpdatedAt { get; set; } diff --git a/DMS.Infrastructure/Profiles/MappingProfile.cs b/DMS.Infrastructure/Profiles/MappingProfile.cs index 0133905..d8ff8b1 100644 --- a/DMS.Infrastructure/Profiles/MappingProfile.cs +++ b/DMS.Infrastructure/Profiles/MappingProfile.cs @@ -27,7 +27,6 @@ public class MappingProfile : Profile .ReverseMap(); CreateMap() - .ForMember(dest => dest.Description, opt => opt.Ignore()) .ForMember(dest => dest.VariableTable, opt => opt.Ignore()) .ForMember(dest => dest.MqttAliases, opt => opt.Ignore()) .ForMember(dest => dest.DataValue, opt => opt.Ignore())