Files
LabelChange-server/Complete_Trigger_Implementation.md
2026-06-01 16:30:29 +08:00

244 lines
7.5 KiB
Markdown
Raw Permalink 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.

# 完整的触发器实现方案
## 1. 需求概述
`label_replace_requests` 表中添加 `LabelRetrievedAt` 字段,用于记录客户获取标签的时间,并通过数据库触发器在插入和更新操作时自动更新该字段。
## 2. 实现步骤
### 2.1 修改数据模型
已在 `LabelReplaceEntity` 类中添加了 `LabelRetrievedAt` 字段:
```csharp
/// <summary>
/// 获取标签时间
/// </summary>
[SugarColumn(IsNullable = true)]
public DateTime? LabelRetrievedAt { get; set; }
```
### 2.2 数据库表结构更新
**方法1使用代码优先方式**
当应用程序启动时SqlSugar 的 CodeFirst 功能会自动创建新字段。
**方法2手动执行SQL语句**
```sql
ALTER TABLE label_replace_requests
ADD COLUMN LabelRetrievedAt DATETIME NULL COMMENT '获取标签时间';
```
### 2.3 创建触发器
#### 2.3.1 INSERT触发器
```sql
DELIMITER $$
CREATE TRIGGER insert_label_retrieved_timestamp
BEFORE INSERT ON label_replace_requests
FOR EACH ROW
BEGIN
-- 当插入数据时提供了Label字段设置LabelRetrievedAt
IF NEW.Label IS NOT NULL THEN
SET NEW.LabelRetrievedAt = UTC_TIMESTAMP();
END IF;
-- 确保CreatedAt和UpdatedAt字段有值
IF NEW.CreatedAt IS NULL THEN
SET NEW.CreatedAt = UTC_TIMESTAMP();
END IF;
IF NEW.UpdatedAt IS NULL THEN
SET NEW.UpdatedAt = UTC_TIMESTAMP();
END IF;
END$$
DELIMITER ;
```
#### 2.3.2 UPDATE触发器
```sql
DELIMITER $$
CREATE TRIGGER update_label_retrieved_timestamp
BEFORE UPDATE ON label_replace_requests
FOR EACH ROW
BEGIN
-- 当Label字段被设置或修改时更新LabelRetrievedAt
IF NEW.Label IS NOT NULL AND (OLD.Label IS NULL OR NEW.Label != OLD.Label) THEN
SET NEW.LabelRetrievedAt = UTC_TIMESTAMP();
END IF;
-- 同时更新UpdatedAt字段
SET NEW.UpdatedAt = UTC_TIMESTAMP();
END$$
DELIMITER ;
```
## 3. 触发器说明
### 3.1 INSERT触发器
- **触发时机**`BEFORE INSERT` 在插入操作执行前触发
- **逻辑说明**:当插入数据时如果提供了 `Label` 字段,自动设置 `LabelRetrievedAt` 为当前时间
- **时间戳设置**:使用 `UTC_TIMESTAMP()` 函数获取当前UTC时间与代码中使用的 `DateTime.UtcNow` 保持一致
### 3.2 UPDATE触发器
- **触发时机**`BEFORE UPDATE` 在更新操作执行前触发
- **逻辑说明**:当 `Label` 字段从 `NULL` 变为非 `NULL`,或其值被修改时,更新 `LabelRetrievedAt` 为当前时间
- **时间戳设置**:同时更新 `UpdatedAt` 字段,保持与现有逻辑一致
## 4. 测试验证
### 4.1 插入操作测试
1. **插入带标签的数据**
```sql
INSERT INTO label_replace_requests (NeutralWaybillNumber, ReplaceStatus, Label)
VALUES ('TEST123456', 'Y', 'base64_encoded_pdf');
```
2. **验证LabelRetrievedAt是否被设置**
```sql
SELECT LabelRetrievedAt, CreatedAt, UpdatedAt FROM label_replace_requests WHERE NeutralWaybillNumber = 'TEST123456';
```
预期结果:`LabelRetrievedAt`、`CreatedAt` 和 `UpdatedAt` 都被设置为当前时间
3. **插入不带标签的数据**
```sql
INSERT INTO label_replace_requests (NeutralWaybillNumber, ReplaceStatus)
VALUES ('TEST789012', 'Y');
```
4. **验证LabelRetrievedAt是否为NULL**
```sql
SELECT LabelRetrievedAt, CreatedAt, UpdatedAt FROM label_replace_requests WHERE NeutralWaybillNumber = 'TEST789012';
```
预期结果:`LabelRetrievedAt` 为 `NULL``CreatedAt` 和 `UpdatedAt` 被设置为当前时间
### 4.2 更新操作测试
1. **更新不带标签的记录,添加标签**
```sql
UPDATE label_replace_requests SET Label = 'base64_encoded_pdf'
WHERE NeutralWaybillNumber = 'TEST789012';
```
2. **验证LabelRetrievedAt是否被更新**
```sql
SELECT LabelRetrievedAt, UpdatedAt FROM label_replace_requests WHERE NeutralWaybillNumber = 'TEST789012';
```
预期结果:`LabelRetrievedAt` 和 `UpdatedAt` 都被更新为当前时间
3. **更新带标签的记录,修改标签**
```sql
UPDATE label_replace_requests SET Label = 'updated_base64_encoded_pdf'
WHERE NeutralWaybillNumber = 'TEST123456';
```
4. **验证LabelRetrievedAt是否被更新**
```sql
SELECT LabelRetrievedAt, UpdatedAt FROM label_replace_requests WHERE NeutralWaybillNumber = 'TEST123456';
```
预期结果:`LabelRetrievedAt` 和 `UpdatedAt` 都被更新为当前时间
5. **更新其他字段**
```sql
UPDATE label_replace_requests SET FinalMileTrackingNumber = 'FM123456'
WHERE NeutralWaybillNumber = 'TEST123456';
```
6. **验证LabelRetrievedAt是否保持不变**
```sql
SELECT LabelRetrievedAt, UpdatedAt FROM label_replace_requests WHERE NeutralWaybillNumber = 'TEST123456';
```
预期结果:`LabelRetrievedAt` 保持不变,`UpdatedAt` 被更新为当前时间
## 5. 注意事项
### 5.1 权限要求
- 需要 `CREATE TRIGGER` 权限
- 需要对 `label_replace_requests` 表有 `TRIGGER` 权限
- 需要对 `label_replace_requests` 表有 `ALTER` 权限(用于添加新字段)
### 5.2 性能影响
- 触发器会在每次插入和更新操作时执行,可能影响高频操作场景的性能
- 建议在生产环境中进行性能测试
### 5.3 维护性
- 触发器逻辑存储在数据库中,与应用代码分离,可能增加维护难度
- 建议在代码中添加注释,说明触发器的存在和功能
### 5.4 兼容性
- 确保MySQL版本支持触发器MySQL 5.0及以上版本支持)
- 不同MySQL版本的触发器语法可能略有差异
## 6. 触发器管理
### 6.1 修改触发器
**修改INSERT触发器**
```sql
-- 先删除旧触发器
DROP TRIGGER IF EXISTS insert_label_retrieved_timestamp;
-- 再创建新触发器
DELIMITER $$
CREATE TRIGGER insert_label_retrieved_timestamp
BEFORE INSERT ON label_replace_requests
FOR EACH ROW
BEGIN
-- 当插入数据时提供了Label字段设置LabelRetrievedAt
IF NEW.Label IS NOT NULL THEN
SET NEW.LabelRetrievedAt = UTC_TIMESTAMP();
END IF;
-- 确保CreatedAt和UpdatedAt字段有值
IF NEW.CreatedAt IS NULL THEN
SET NEW.CreatedAt = UTC_TIMESTAMP();
END IF;
IF NEW.UpdatedAt IS NULL THEN
SET NEW.UpdatedAt = UTC_TIMESTAMP();
END IF;
END$$
DELIMITER ;
```
**修改UPDATE触发器**
```sql
-- 先删除旧触发器
DROP TRIGGER IF EXISTS update_label_retrieved_timestamp;
-- 再创建新触发器
DELIMITER $$
CREATE TRIGGER update_label_retrieved_timestamp
BEFORE UPDATE ON label_replace_requests
FOR EACH ROW
BEGIN
-- 当Label字段被设置或修改时更新LabelRetrievedAt
IF NEW.Label IS NOT NULL AND (OLD.Label IS NULL OR NEW.Label != OLD.Label) THEN
SET NEW.LabelRetrievedAt = UTC_TIMESTAMP();
END IF;
-- 同时更新UpdatedAt字段
SET NEW.UpdatedAt = UTC_TIMESTAMP();
END$$
DELIMITER ;
```
### 6.2 删除触发器
```sql
-- 删除INSERT触发器
DROP TRIGGER IF EXISTS insert_label_retrieved_timestamp;
-- 删除UPDATE触发器
DROP TRIGGER IF EXISTS update_label_retrieved_timestamp;
```
## 7. 总结
通过创建INSERT和UPDATE触发器可以在数据库层面自动记录客户获取标签的时间。这种方法的优点是
1. **自动记录**:无需在应用代码中手动设置,触发器会自动处理
2. **完整性**:覆盖了插入和更新两种操作场景
3. **准确性**:仅在标签被设置或修改时才更新时间戳
4. **一致性**:与现有的时间戳更新逻辑保持一致
在实际应用中,应根据系统的具体情况(如操作频率、性能要求等)选择合适的实现方式。