@@ -0,0 +1,68 @@
|
||||
# Database Guidelines
|
||||
|
||||
> Database patterns and conventions for this project.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
<!--
|
||||
Document your project's database conventions here.
|
||||
|
||||
Questions to answer:
|
||||
- What ORM/query library do you use?
|
||||
- How are migrations managed?
|
||||
- What are the naming conventions for tables/columns?
|
||||
- How do you handle transactions?
|
||||
-->
|
||||
|
||||
(To be filled by the team)
|
||||
|
||||
---
|
||||
|
||||
## Query Patterns
|
||||
|
||||
<!-- How should queries be written? Batch operations? -->
|
||||
|
||||
(To be filled by the team)
|
||||
|
||||
---
|
||||
|
||||
## Migrations
|
||||
|
||||
<!-- How to create and run migrations -->
|
||||
|
||||
(To be filled by the team)
|
||||
|
||||
---
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
<!-- Table names, column names, index names -->
|
||||
|
||||
(To be filled by the team)
|
||||
|
||||
---
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
<!-- Database-related mistakes your team has made -->
|
||||
|
||||
### Common Mistake: gorm 读 NULL 列到已有值的结构体字段不会清零
|
||||
|
||||
**Symptom**:UPDATE 把可空列(如 `*time.Time`)写成 NULL 后,用**同一个结构体变量**再次 `First()` 读回,该字段仍是旧值;而新变量读取正常。断言/返回值出现「幽灵旧值」。
|
||||
|
||||
**Cause**:gorm Scan 遇到 NULL 列时跳过赋值(保持字段现状),不会主动置 nil。复用变量(循环内重读、更新后回读同一 &ch)时旧值残留。
|
||||
|
||||
**Fix**:更新后回读一律用新变量(`var fresh model.X; db.First(&fresh, id)`)。
|
||||
|
||||
**Prevention**:凡「UPDATE 后回读返回」的服务方法,都声明新变量接收;测试中多次 `First` 同一行也各用独立变量。另:map Updates 写 NULL 用 `gorm.Expr("NULL")` 最稳(无类型 `nil` 在部分路径下不生效)。
|
||||
|
||||
### Common Mistake: 需要"条件更新多列含 NULL"时的写法
|
||||
|
||||
```go
|
||||
// 正确:零写库条件 + 显式 NULL
|
||||
db.Model(&model.AiChannel{}).
|
||||
Where("id = ? AND (fail_count > 0 OR disabled_until IS NOT NULL)", id).
|
||||
Updates(map[string]any{"fail_count": 0, "disabled_until": gorm.Expr("NULL")})
|
||||
```
|
||||
Reference in New Issue
Block a user