# 软件开发文档 - DMS.Core 领域模型与接口 本文档详细阐述了 `DMS.Core` 项目的设计,它是整个系统的基石,包含所有业务实体和核心接口的定义。`DMS.Core` 不包含任何具体实现,确保了业务规则的独立性和可移植性。 ## 1. 目录结构 ``` DMS.Core/ ├── Enums/ │ ├── PollLevelType.cs │ ├── ProtocolType.cs │ └── SignalType.cs ├── Models/ │ ├── Device.cs │ ├── MqttServer.cs │ ├── Variable.cs │ ├── VariableHistory.cs │ ├── VariableMqttAlias.cs │ ├── VariableTable.cs │ ├── MenuBean.cs │ └── User.cs ├── Interfaces/ │ ├── IRepositoryManager.cs │ ├── IBaseRepository.cs │ ├── IDeviceRepository.cs │ ├── IMqttServerRepository.cs │ ├── IVariableHistoryRepository.cs │ ├── IVariableMqttAliasRepository.cs │ ├── IVariableRepository.cs │ ├── IVariableTableRepository.cs │ ├── IMenuRepository.cs │ └── IUserRepository.cs └── DMS.Core.csproj ``` ## 2. 核心枚举 (`Enums/`) 使用C#枚举来表示业务中固定的、有限的分类,如协议类型、信号类型、轮询级别。这提供了类型安全和代码可读性。 ### `PollLevelType.cs` ```csharp // 文件: DMS.Core/Enums/PollLevelType.cs using System.ComponentModel; namespace DMS.Core.Enums; public enum PollLevelType { [Description("10毫秒")] TenMilliseconds = 10, [Description("100毫秒")] HundredMilliseconds = 100, [Description("500毫秒")] FiveHundredMilliseconds = 500, [Description("1秒钟")] OneSecond = 1000, [Description("5秒钟")] FiveSeconds = 5000, [Description("10秒钟")] TenSeconds = 10000, [Description("20秒钟")] TwentySeconds = 20000, [Description("30秒钟")] ThirtySeconds = 30000, [Description("1分钟")] OneMinute = 60000, [Description("3分钟")] ThreeMinutes = 180000, [Description("5分钟")] FiveMinutes = 300000, [Description("10分钟")] TenMinutes = 600000, [Description("30分钟")] ThirtyMinutes = 1800000, [Description("1小时")] OneHour = 3600000 } ``` ### `ProtocolType.cs` ```csharp // 文件: DMS.Core/Enums/ProtocolType.cs /// /// 定义了设备支持的通信协议类型。 /// public enum ProtocolType { /// /// Siemens S7 通信协议。 /// S7, /// /// OPC UA (Unified Architecture) 协议。 /// OpcUa, /// /// Modbus TCP 协议。 /// ModbusTcp } ``` ### `SignalType.cs` ```csharp // 文件: DMS.Core/Enums/SignalType.cs using System.ComponentModel; namespace DMS.Core.Enums; public enum SignalType { [Description("启动信号")] StartSignal, [Description("停止信号")] StopSignal, [Description("报警信号")] AlarmSignal, [Description("准备信号")] ReadySignal, [Description("复位信号")] ResetSignal, [Description("运行信号")] RunSignal, [Description("设定频率")] SetHZSignal, [Description("当前频率")] GetHZSignal, [Description("当前电流")] CurrentASignal, [Description("其他信号")] OtherASignal } /// /// 定义了C#中常用的数据类型。 /// public enum CSharpDataType { [Description("布尔型")] Bool, [Description("字节型")] Byte, [Description("短整型")] Short, [Description("整型")] Int, [Description("长整型")] Long, [Description("浮点型")] Float, [Description("双精度浮点型")] Double, [Description("字符串型")] String, [Description("日期时间型")] DateTime, [Description("时间跨度型")] TimeSpan, [Description("对象型")] Object, [Description("未知类型")] Unknown } ``` ## 3. 领域模型 (`Models/`) 领域模型是业务核心的C#类表示。它们是贫血模型,主要包含数据属性,行为逻辑则由应用服务和领域服务处理。模型之间通过导航属性建立关系,反映业务实体间的关联。 ### `Device.cs` ```csharp // 文件: DMS.Core/Models/Device.cs /// /// 代表一个可管理的物理或逻辑设备。 /// public class Device { /// /// 唯一标识符。 /// public int Id { get; set; } /// /// 设备名称,用于UI显示和识别。 /// public string Name { get; set; } /// /// 设备的描述信息。 /// public string Description { get; set; } /// /// 设备使用的通信协议。 /// public ProtocolType Protocol { get; set; } /// /// 设备的IP地址。 /// public string IpAddress { get; set; } /// /// 设备的通信端口号。 /// public int Port { get; set; } /// /// S7 PLC的机架号。 /// public int Rack { get; set; } /// /// S7 PLC的槽号。 /// public int Slot { get; set; } /// /// OPC UA 服务器地址 (仅当 Protocol 为 OpcUa 时有效)。 /// public string OpcUaServerUrl { get; set; } /// /// 指示此设备是否处于激活状态。只有激活的设备才会被轮询。 /// public bool IsActive { get; set; } /// /// 此设备包含的变量表集合。 /// public List VariableTables { get; set; } = new(); } ``` ### `VariableTable.cs` ```csharp // 文件: DMS.Core/Models/VariableTable.cs namespace DMS.Core.Models; /// /// 组织和管理一组相关的变量。 /// public class VariableTable { public int Id { get; set; } public string Name { get; set; } public string Description { get; set; } public bool IsActive { get; set; } // 是否启用 public int DeviceId { get; set; } public Device Device { get; set; } public ProtocolType Protocol { get; set; } // 通讯协议 public List Variables { get; set; } = new(); } ``` ### `Variable.cs` ```csharp // 文件: DMS.Core/Models/Variable.cs /// /// 核心数据点,代表从设备读取的单个值。 /// public class Variable { /// /// 唯一标识符。 /// public int Id { get; set; } /// /// 变量名。 /// public string Name { get; set; } /// /// 变量的描述信息。 /// public string Description { get; set; } /// /// 在设备中的地址 (例如: DB1.DBD0, M100.0)。 /// public string Address { get; set; } /// /// 变量的信号类型,例如启动信号、停止信号。 /// public SignalType DataType { get; set; } /// /// 变量的轮询级别,决定了其读取频率。 /// public PollLevelType PollLevel { get; set; } /// /// 指示此变量是否处于激活状态。 /// public bool IsActive { get; set; } /// /// 所属变量表的ID。 /// public int VariableTableId { get; set; } /// /// 所属变量表的导航属性。 /// public VariableTable VariableTable { get; set; } /// /// 此变量的所有MQTT发布别名关联。一个变量可以关联多个MQTT服务器,每个关联可以有独立的别名。 /// public List MqttAliases { get; set; } = new(); /// /// OPC UA NodeId (仅当 Protocol 为 OpcUa 时有效)。 /// public string OpcUaNodeId { get; set; } /// /// 是否启用历史数据保存。 /// public bool IsHistoryEnabled { get; set; } /// /// 历史数据保存的死区值。当变量值变化超过此死区时才保存。 /// public double HistoryDeadband { get; set; } /// /// 是否启用报警。 /// public bool IsAlarmEnabled { get; set; } /// /// 报警最小值。 /// public double AlarmMinValue { get; set; } /// /// 报警最大值。 /// public double AlarmMaxValue { get; set; } /// /// 报警死区。当变量值变化超过此死区时才触发报警。 /// public double AlarmDeadband { get; set; } /// /// 存储从设备读取到的最新值。此属性不应持久化到数据库,仅用于运行时。 /// [System.ComponentModel.DataAnnotations.Schema.NotMapped] // 标记此属性不映射到数据库 public object DataValue { get; set; } /// /// 变量的通讯协议。 /// public ProtocolType Protocol { get; set; } /// /// 变量的数据类型。 /// public CSharpDataType CSharpDataType { get; set; } /// /// 数值转换公式,例如 "+3*5"。 /// public string ConversionFormula { get; set; } /// /// 经过转换公式计算后的显示值。此属性不应持久化到数据库,仅用于运行时。 /// [System.ComponentModel.DataAnnotations.Schema.NotMapped] public object DisplayValue { get; set; } /// /// 变量的创建时间。 /// public DateTime CreatedAt { get; set; } /// /// 变量的最后更新时间。 /// public DateTime UpdatedAt { get; set; } /// /// 最后更新变量的用户。 /// public string UpdatedBy { get; set; } /// /// 指示变量是否被修改。 /// public bool IsModified { get; set; } } ``` ### `MqttServer.cs` ```csharp // 文件: DMS.Core/Models/MqttServer.cs namespace DMS.Core.Models; /// /// 代表一个MQTT Broker的配置。 /// public class MqttServer { public int Id { get; set; } public string ServerName { get; set; } public string BrokerAddress { get; set; } // Broker地址 public int Port { get; set; } // 端口 public string Username { get; set; } // 用户名 public string Password { get; set; } // 密码 public bool IsActive { get; set; } // 是否启用 /// /// MQTT订阅主题。 /// public string SubscribeTopic { get; set; } /// /// MQTT发布主题。 /// public string PublishTopic { get; set; } /// /// MQTT客户端ID。 /// public string ClientId { get; set; } /// /// MQTT服务器配置的创建时间。 /// public DateTime CreatedAt { get; set; } /// /// MQTT客户端连接到Broker的时间。 /// public DateTime? ConnectedAt { get; set; } /// /// MQTT客户端连接时长(秒)。 /// public long ConnectionDuration { get; set; } /// /// 报文格式,例如JSON, PlainText等。 /// public string MessageFormat { get; set; } /// /// 与此服务器关联的所有变量别名。通过此集合可以反向查找关联的变量。 /// public List VariableAliases { get; set; } = new(); } ``` ### `VariableHistory.cs` ```csharp // 文件: DMS.Core/Models/VariableHistory.cs namespace DMS.Core.Models; /// /// 用于存储变量值的变化记录。 /// public class VariableHistory { public long Id { get; set; } public int VariableId { get; set; } public string Value { get; set; } // 以字符串形式存储,便于通用性 public DateTime Timestamp { get; set; } } ``` ### `VariableMqttAlias.cs` ```csharp // 文件: DMS.Core/Models/VariableMqttAlias.cs /// /// 领域模型:代表一个变量到一个MQTT服务器的特定关联,包含专属别名。 /// 这是一个关联实体,用于解决多对多关系中需要额外属性(别名)的问题。 /// public class VariableMqttAlias { /// /// 唯一标识符。 /// public int Id { get; set; } /// /// 关联的变量ID。 /// public int VariableId { get; set; } /// /// 关联的MQTT服务器ID。 /// public int MqttServerId { get; set; } /// /// 针对此特定[变量-服务器]连接的发布别名。此别名将用于构建MQTT Topic。 /// public string Alias { get; set; } /// /// 关联的变量导航属性。 /// public Variable Variable { get; set; } /// /// 关联的MQTT服务器导航属性。 /// public MqttServer MqttServer { get; set; } } ``` ### `MenuBean.cs` ```csharp // 文件: DMS.Core/Models/MenuBean.cs namespace DMS.Core.Models; /// /// 领域模型:代表一个菜单项。 /// public class MenuBean { public int Id { get; set; } public int? ParentId { get; set; } public string Header { get; set; } public string Icon { get; set; } public string TargetViewKey { get; set; } public string NavigationParameter { get; set; } public int DisplayOrder { get; set; } } ``` ### `User.cs` ```csharp // 文件: DMS.Core/Models/User.cs namespace DMS.Core.Models; /// /// 领域模型:代表一个用户。 /// public class User { public int Id { get; set; } public string Username { get; set; } public string PasswordHash { get; set; } // 存储密码哈希值 public string Role { get; set; } // 用户角色,例如 "Admin", "Operator" public bool IsActive { get; set; } } ``` ## 4. 核心接口 (`Interfaces/`) ### 4.1. `IRepositoryManager.cs` (工作单元模式) 定义了一个仓储管理器,它使用工作单元模式来组合多个仓储操作,以确保事务的原子性。它作为所有仓储的统一入口,并管理数据库事务。 ```csharp // 文件: DMS.Core/Interfaces/IRepositoryManager.cs namespace DMS.Core.Interfaces; /// /// 定义了一个仓储管理器,它使用工作单元模式来组合多个仓储操作,以确保事务的原子性。 /// 实现了IDisposable,以确保数据库连接等资源能被正确释放。 /// public interface IRepositoryManager : IDisposable { /// /// 获取设备仓储的实例。 /// 所有通过此管理器获取的仓储都共享同一个数据库上下文和事务。 /// IDeviceRepository Devices { get; } /// /// 获取变量表仓储的实例。 /// IVariableTableRepository VariableTables { get; } /// /// 获取变量仓储的实例。 /// IVariableRepository Variables { get; } /// /// 获取MQTT服务器仓储的实例。 /// IMqttServerRepository MqttServers { get; } /// /// 获取变量MQTT别名仓储的实例。 /// IVariableMqttAliasRepository VariableMqttAliases { get; } /// /// 获取菜单仓储的实例。 /// IMenuRepository Menus { get; } /// /// 获取变量历史仓储的实例。 /// IVariableHistoryRepository VariableHistories { get; } /// /// 获取用户仓储的实例。 /// IUserRepository Users { get; } /// /// 开始一个新的数据库事务。 /// void BeginTransaction(); /// /// 异步提交当前事务中的所有变更。 /// /// 一个表示异步操作的任务。 Task CommitAsync(); /// /// 异步回滚当前事务中的所有变更。 /// /// 一个表示异步操作的任务。 Task RollbackAsync(); } ``` ### 4.2. 仓储接口 (`IBaseRepository.cs`, `IDeviceRepository.cs` 等) 采用仓储(Repository)模式,为每个聚合根(或主要实体)定义一个数据访问接口。这些接口定义了对领域对象集合的操作,隐藏了底层数据存储的细节。 #### `IBaseRepository.cs` ```csharp // 文件: DMS.Core/Interfaces/IBaseRepository.cs namespace DMS.Core.Interfaces; /// /// 提供泛型数据访问操作的基础仓储接口。 /// /// 领域模型的类型。 public interface IBaseRepository where T : class { /// /// 异步根据ID获取单个实体。 /// /// 实体的主键ID。 /// 找到的实体,如果不存在则返回null。 Task GetByIdAsync(int id); /// /// 异步获取所有实体。 /// /// 所有实体的列表。 Task> GetAllAsync(); /// /// 异步添加一个新实体。 /// /// 要添加的实体。 Task AddAsync(T entity); /// /// 异步更新一个已存在的实体。 /// /// 要更新的实体。 Task UpdateAsync(T entity); /// /// 异步根据ID删除一个实体。 /// /// 要删除的实体的主键ID。 Task DeleteAsync(int id); } ``` #### `IDeviceRepository.cs` ```csharp // 文件: DMS.Core/Interfaces/IDeviceRepository.cs using DMS.Core.Models; namespace DMS.Core.Interfaces; /// /// 继承自IBaseRepository,提供设备相关的特定数据查询功能。 /// public interface IDeviceRepository : IBaseRepository { /// /// 异步获取所有激活的设备,并级联加载其下的变量表和变量。 /// 这是后台轮询服务需要的主要数据。 /// /// 包含完整层级结构的激活设备列表。 Task> GetActiveDevicesWithDetailsAsync(ProtocolType protocol); /// /// 异步根据设备ID获取设备及其所有详细信息(变量表、变量、MQTT别名等)。 /// /// 设备ID。 /// 包含详细信息的设备对象。 Task GetDeviceWithDetailsAsync(int deviceId); } ``` #### `IVariableRepository.cs` ```csharp // 文件: DMS.Core/Interfaces/IVariableRepository.cs using DMS.Core.Models; namespace DMS.Core.Interfaces; public interface IVariableRepository : IBaseRepository { /// /// 异步获取一个变量及其关联的所有MQTT别名和对应的MQTT服务器信息。 /// /// 变量ID。 /// 包含别名和服务器信息的变量对象。 Task GetVariableWithMqttAliasesAsync(int variableId); } ``` #### `IMqttServerRepository.cs` ```csharp // 文件: DMS.Core/Interfaces/IMqttServerRepository.cs using DMS.Core.Models; namespace DMS.Core.Interfaces; public interface IMqttServerRepository : IBaseRepository { /// /// 异步获取一个MQTT服务器及其关联的所有变量别名。 /// /// MQTT服务器ID。 /// 包含变量别名信息的MQTT服务器对象。 Task GetMqttServerWithVariableAliasesAsync(int serverId); } ``` #### `IVariableTableRepository.cs` ```csharp // 文件: DMS.Core/Interfaces/IVariableTableRepository.cs using DMS.Core.Models; namespace DMS.Core.Interfaces; public interface IVariableTableRepository : IBaseRepository { // 可以添加特定于VariableTable的查询方法 } ``` #### `IVariableHistoryRepository.cs` ```csharp // 文件: DMS.Core/Interfaces/IVariableHistoryRepository.cs using DMS.Core.Models; namespace DMS.Core.Interfaces; public interface IVariableHistoryRepository : IBaseRepository { // 可以添加特定于VariableHistory的查询方法 } ``` #### `IVariableMqttAliasRepository.cs` ```csharp // 文件: DMS.Core/Interfaces/IVariableMqttAliasRepository.cs using DMS.Core.Models; namespace DMS.Core.Interfaces; public interface IVariableMqttAliasRepository : IBaseRepository { /// /// 异步获取指定变量的所有MQTT别名关联,并加载关联的MQTT服务器信息。 /// /// 变量ID。 /// 指定变量的所有MQTT别名关联列表。 Task> GetAliasesForVariableAsync(int variableId); /// /// 异步根据变量ID和MQTT服务器ID获取特定的MQTT别名关联。 /// /// 变量ID。 /// MQTT服务器ID。 /// 匹配的VariableMqttAlias对象,如果不存在则为null。 Task GetByVariableAndServerAsync(int variableId, int mqttServerId); } ``` #### `IMenuRepository.cs` ```csharp // 文件: DMS.Core/Interfaces/IMenuRepository.cs using DMS.Core.Models; namespace DMS.Core.Interfaces; public interface IMenuRepository : IBaseRepository { // 可以添加特定于菜单的查询方法,例如获取所有菜单项 } ``` #### `IUserRepository.cs` ```csharp // 文件: DMS.Core/Interfaces/IUserRepository.cs using DMS.Core.Models; namespace DMS.Core.Interfaces; public interface IUserRepository : IBaseRepository { /// /// 异步根据用户名获取用户。 /// /// 用户名。 /// 用户对象,如果不存在则为null。 Task GetByUsernameAsync(string username); } ```