Files
WCTDataMiner/docs/data-model/entities/测试场景.md
ssss 28cb2533a7 docs: 完善数据模型设计
- 重命名 log_file 为 test_scenario(测试场景)
- 拆分维度表:tx_panel、tx_hardware、tx_software、rx_type
- 采用星型模型设计,消除数据冗余
- 为所有表添加软删除字段 is_deleted
- 更新关系说明,包含全局查询过滤器配置
- 更新 ER 图和查询示例

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 15:53:30 +08:00

230 lines
6.7 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.
# test_scenario 实体
> 所属模块:[数据模型概览](../概览.md)
---
## 1. 表定义
**表名**`test_scenario`
**描述**存储测试场景通过外键关联各维度表test_purpose 直接存储
---
## 2. 字段定义
| 列名 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | UUID | PK, NOT NULL | 主键,自动生成 |
| tx_panel_id | UUID | FK, NOT NULL | 关联TX面板维度 |
| tx_hardware_id | UUID | FK, NOT NULL | 关联TX硬件版本维度 |
| tx_software_id | UUID | FK, NOT NULL | 关联TX软件版本维度 |
| rx_type_id | UUID | FK, NOT NULL | 关联RX类型维度 |
| test_purpose | VARCHAR(200) | NULL | 测试目的(直接存储) |
| test_date | DATE | NOT NULL | 测试日期 |
| test_sequence | INT | NOT NULL, DEFAULT 1 | 测试次数序号 |
| qfod_count | INT | NOT NULL, DEFAULT 0 | 包含的 Qfod 记录数 |
| ploss_count | INT | NOT NULL, DEFAULT 0 | 包含的 Ploss 记录数 |
| is_deleted | BOOLEAN | NOT NULL, DEFAULT FALSE | 软删除标记 |
| created_at | TIMESTAMP | NOT NULL, DEFAULT NOW() | 入库时间 |
---
## 3. 外键
| 外键 | 引用表 | 说明 |
|------|--------|------|
| tx_panel_id | tx_panel.id | 关联TX面板维度必需 |
| tx_hardware_id | tx_hardware.id | 关联TX硬件版本维度必需 |
| tx_software_id | tx_software.id | 关联TX软件版本维度必需 |
| rx_type_id | rx_type.id | 关联RX类型维度必需 |
---
## 4. 索引
| 索引名 | 字段 | 用途 |
|--------|------|------|
| idx_scenario_tx_panel | tx_panel_id | 按面板类型筛选 |
| idx_scenario_tx_hardware | tx_hardware_id | 按硬件版本筛选 |
| idx_scenario_tx_software | tx_software_id | 按软件版本筛选 |
| idx_scenario_rx_type | rx_type_id | 按RX类型筛选 |
| idx_scenario_test_date | test_date | 按测试日期查询 |
---
## 5. 唯一约束
| 约束名 | 字段组合 | 说明 |
|--------|----------|------|
| uq_scenario | (tx_panel_id, tx_hardware_id, tx_software_id, rx_type_id, test_purpose, test_date, test_sequence) | 相同属性组合不重复创建 |
---
## 6. EF Core 模型
```csharp
// Models/TestScenario.cs
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace WCTDataMiner.Models;
[Table("test_scenario")]
[Index(nameof(TxPanelId), Name = "idx_scenario_tx_panel")]
[Index(nameof(TxHardwareId), Name = "idx_scenario_tx_hardware")]
[Index(nameof(TxSoftwareId), Name = "idx_scenario_tx_software")]
[Index(nameof(RxTypeId), Name = "idx_scenario_rx_type")]
[Index(nameof(TestDate), Name = "idx_scenario_test_date")]
public class TestScenario
{
[Key]
[Column("id")]
public Guid Id { get; set; } = Guid.NewGuid();
[Required]
[Column("tx_panel_id")]
public Guid TxPanelId { get; set; }
[Required]
[Column("tx_hardware_id")]
public Guid TxHardwareId { get; set; }
[Required]
[Column("tx_software_id")]
public Guid TxSoftwareId { get; set; }
[Required]
[Column("rx_type_id")]
public Guid RxTypeId { get; set; }
[MaxLength(200)]
[Column("test_purpose")]
public string? TestPurpose { get; set; }
[Required]
[Column("test_date")]
public DateOnly TestDate { get; set; }
[Required]
[Column("test_sequence")]
public int TestSequence { get; set; } = 1;
[Required]
[Column("qfod_count")]
public int QfodCount { get; set; } = 0;
[Required]
[Column("ploss_count")]
public int PlossCount { get; set; } = 0;
[Required]
[Column("is_deleted")]
public bool IsDeleted { get; set; } = false;
[Required]
[Column("created_at")]
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
// Navigation Properties - 维度表
[ForeignKey(nameof(TxPanelId))]
public TxPanel TxPanel { get; set; } = null!;
[ForeignKey(nameof(TxHardwareId))]
public TxHardware TxHardware { get; set; } = null!;
[ForeignKey(nameof(TxSoftwareId))]
public TxSoftware TxSoftware { get; set; } = null!;
[ForeignKey(nameof(RxTypeId))]
public RxType RxType { get; set; } = null!;
// Navigation Properties - 数据记录
public ICollection<QfodRecord> QfodRecords { get; set; } = [];
public ICollection<PlossRecord> PlossRecords { get; set; } = [];
}
```
---
## 7. 场景创建流程
### 从文件名解析
```csharp
// Services/ScenarioService.cs
public async Task<TestScenario> GetOrCreateFromFileNameAsync(string fileName)
{
// 1. 解析文件名
var parts = ParseFileName(fileName);
// 格式: TX面板-TX硬件-TX软件-RX类型-测试目的-年月日-测试次数.log
// 2. 获取或创建各维度
var txPanel = await txPanelService.GetOrCreateAsync(parts.TxPanel);
var txHardware = await txHardwareService.GetOrCreateAsync(parts.TxHardware);
var txSoftware = await txSoftwareService.GetOrCreateAsync(parts.TxSoftware);
var rxType = await rxTypeService.GetOrCreateAsync(parts.RxType);
// 3. 检查场景是否已存在
var existing = await context.TestScenarios
.FirstOrDefaultAsync(s =>
s.TxPanelId == txPanel.Id &&
s.TxHardwareId == txHardware.Id &&
s.TxSoftwareId == txSoftware.Id &&
s.RxTypeId == rxType.Id &&
s.TestPurpose == parts.TestPurpose &&
s.TestDate == parts.TestDate &&
s.TestSequence == parts.TestSequence);
if (existing != null) return existing;
// 4. 创建新场景
var scenario = new TestScenario
{
TxPanelId = txPanel.Id,
TxHardwareId = txHardware.Id,
TxSoftwareId = txSoftware.Id,
RxTypeId = rxType.Id,
TestPurpose = parts.TestPurpose,
TestDate = parts.TestDate,
TestSequence = parts.TestSequence
};
context.TestScenarios.Add(scenario);
await context.SaveChangesAsync();
return scenario;
}
```
### 手动创建
```csharp
public async Task<TestScenario> CreateAsync(CreateScenarioRequest request)
{
// 1. 验证维度是否存在
var txPanel = await context.TxPanels.FindAsync(request.TxPanelId)
?? throw new NotFoundException("TX面板不存在");
var txHardware = await context.TxHardwares.FindAsync(request.TxHardwareId)
?? throw new NotFoundException("TX硬件版本不存在");
// ... 其他维度验证
// 2. 创建场景
var scenario = new TestScenario
{
TxPanelId = request.TxPanelId,
TxHardwareId = request.TxHardwareId,
TxSoftwareId = request.TxSoftwareId,
RxTypeId = request.RxTypeId,
TestPurpose = request.TestPurpose,
TestDate = request.TestDate,
TestSequence = request.TestSequence
};
context.TestScenarios.Add(scenario);
await context.SaveChangesAsync();
return scenario;
}
```