Files
WCTDataMiner/docs/data-model/entities/测试场景.md

230 lines
6.7 KiB
Markdown
Raw Normal View History

# 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;
}
```