Files
DMS/软件设计文档/10-变量与MQTT别名设计.md

180 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 软件开发文档 - 10. 变量与MQTT别名设计
本文档详细阐述了为满足“一个变量在关联不同MQTT服务器时可以有不同别名”这一需求而设计的“关联实体”架构方案。
## 1. 设计挑战与解决方案
**挑战**:一个简单的多对多映射表无法存储“关系”本身的数据(即“别名”)。我们需要一个能将别名属性牢固地绑定在“变量-服务器”这一特定连接上的机制。
**解决方案**:引入一个功能完整的“**关联实体**”Association Entity我们将其命名为 `VariableMqttAlias`。这个实体不仅连接了 `Variable``MqttServer`,它自身还携带了数据(`Alias` 属性),完美地解决了问题。
## 2. 数据库与核心模型设计
我们将用新的 `VariableMqttAlias` 实体来取代之前简单的多对多映射表。
### 2.1. 数据库实体 (`DMS.Infrastructure`)
```csharp
// 文件: DMS.Infrastructure/Entities/DbVariableMqttAlias.cs
using SqlSugar;
namespace DMS.Infrastructure.Entities;
/// <summary>
/// 关联实体连接变量和MQTT服务器并存储该连接专属的别名。
/// </summary>
[SugarTable("VariableMqttAliases")]
public class DbVariableMqttAlias
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
/// <summary>
/// 外键,指向 Variables 表。
/// </summary>
public int VariableId { get; set; }
/// <summary>
/// 外键,指向 MqttServers 表。
/// </summary>
public int MqttServerId { get; set; }
/// <summary>
/// 针对此特定[变量-服务器]连接的发布别名。
/// </summary>
[SugarColumn(Length = 200)]
public string Alias { get; set; }
}
```
### 2.2. 领域模型 (`DMS.Core`)
`Variable``MqttServer` 的领域模型现在通过 `VariableMqttAlias` 间接关联。
```csharp
// 文件: DMS.Core/Models/VariableMqttAlias.cs (新增)
public class VariableMqttAlias
{
public int Id { get; set; }
public int VariableId { get; set; }
public int MqttServerId { get; set; }
public string Alias { get; set; }
public Variable Variable { get; set; }
public MqttServer MqttServer { get; set; }
}
// 文件: DMS.Core/Models/Variable.cs (修改)
public class Variable
{
// ... 其他属性
// 移除: public List<MqttServer> MqttServers { get; set; }
public List<VariableMqttAlias> MqttAliases { get; set; } = new();
}
// 文件: DMS.Core/Models/MqttServer.cs (修改)
public class MqttServer
{
// ... 其他属性
// 移除: public List<Variable> Variables { get; set; }
public List<VariableMqttAlias> VariableAliases { get; set; } = new();
}
```
## 3. 数据处理链更新 (`DMS.Infrastructure`)
`MqttPublishProcessor` 现在必须使用新的关联实体来获取别名和目标服务器。
```csharp
// 文件: DMS.Infrastructure/Services/Processors/MqttPublishProcessor.cs (修改)
public class MqttPublishProcessor : VariableProcessorBase
{
private readonly IMqttPublishService _mqttService;
private readonly IRepositoryManager _repoManager;
public MqttPublishProcessor(IMqttPublishService mqttService, IRepositoryManager repoManager) { /*...*/ }
protected override async Task HandleAsync(VariableContext context)
{
if (!context.IsValueChanged) return;
// 1. 获取变量及其完整的别名关联列表
var variableWithAliases = await _repoManager.Variables.GetWithAliasesAsync(context.Variable.Id);
if (variableWithAliases?.MqttAliases == null) return;
// 2. 遍历每一个“别名关联”
foreach (var aliasInfo in variableWithAliases.MqttAliases)
{
var targetServer = aliasInfo.MqttServer;
if (targetServer == null || !targetServer.IsActive) continue;
// 3. 使用别名构建Topic
var topic = $"devices/{variableWithAliases.VariableTable.Device.Name}/{aliasInfo.Alias}";
var payload = System.Text.Json.JsonSerializer.Serialize(new { value = context.CurrentValue, timestamp = context.Timestamp });
await _mqttService.PublishAsync(targetServer, topic, payload);
}
}
}
```
## 4. 应用层支持 (`DMS.Application`)
为了让UI能够管理这些别名应用层需要提供相应的CRUD服务。
### 4.1. 新DTO
```csharp
// 文件: DMS.Application/DTOs/VariableMqttAliasDto.cs
public class VariableMqttAliasDto
{
public int Id { get; set; }
public int VariableId { get; set; }
public int MqttServerId { get; set; }
public string MqttServerName { get; set; }
public string Alias { get; set; }
}
```
### 4.2. 应用服务接口扩展
`IVariableAppService` 或一个新的 `IMqttAliasAppService` 需要提供管理别名的方法。
```csharp
// 示例接口
public interface IMqttAliasAppService
{
Task<List<VariableMqttAliasDto>> GetAliasesForVariableAsync(int variableId);
Task AssignAliasAsync(int variableId, int mqttServerId, string alias);
Task UpdateAliasAsync(int aliasId, string newAlias);
Task RemoveAliasAsync(int aliasId);
}
```
### 4.3. 应用服务实现
服务实现将使用 `IRepositoryManager` 来操作 `VariableMqttAlias` 仓储。
```csharp
// 示例实现
public class MqttAliasAppService : IMqttAliasAppService
{
private readonly IRepositoryManager _repoManager;
private readonly IMapper _mapper;
public async Task AssignAliasAsync(int variableId, int mqttServerId, string alias)
{
var newAlias = new VariableMqttAlias
{
VariableId = variableId,
MqttServerId = mqttServerId,
Alias = alias
};
await _repoManager.VariableMqttAliases.AddAsync(newAlias);
await _repoManager.CommitAsync();
}
// ... 其他方法的实现
}
```
**注意**:此设计要求为 `VariableMqttAlias` 创建一个专属的仓储接口 (`IVariableMqttAliasRepository`) 和实现,并将其添加到 `IRepositoryManager` 中。