上传源代码版本
This commit is contained in:
244
Complete_Trigger_Implementation.md
Normal file
244
Complete_Trigger_Implementation.md
Normal file
@@ -0,0 +1,244 @@
|
||||
# 完整的触发器实现方案
|
||||
|
||||
## 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. **一致性**:与现有的时间戳更新逻辑保持一致
|
||||
|
||||
在实际应用中,应根据系统的具体情况(如操作频率、性能要求等)选择合适的实现方式。
|
||||
Reference in New Issue
Block a user