GORM v1.30 的 gorm.G[T]:泛型 API 与链式 API 并存,复用实例不再污染 SQL
GORM 从 v1.30.0 起正式支持 Go Generics,入口是 gorm.G[T]。传统链式 API 保持完全向后兼容,两套写法可以混用。泛型 API 要解决两件事:减少复用 gorm.DB 实例导致的 SQL 条件污染,以及提升类型安全。为了避免误用,泛型版有意移除了 FirstOrCreate 和 Save。官方也在设计 gorm CLI 工具,做更强的代码生成。
func G[T any](db *DB, opts ...clause.Expression) Interface[T]
CRUD 写法
ctx := context.Background()
gorm.G[User](db).Create(ctx, &User{Name: "Alice"})
gorm.G[User](db).CreateInBatches(ctx, users, 10)
user, err := gorm.G[User](db).Where("name = ?", "Jinzhu").First(ctx)
users, err := gorm.G[User](db).Where("age ?", 14)
return nil
}).Find(ctx)
users, err = gorm.G[User](db).
Preload("Friends", func(db gorm.PreloadBuilder) error {
db.Select("id", "name").Order("age desc")
return nil
}).
Preload("Friends.Pets", func(db gorm.PreloadBuilder) error {
db.LimitPerRecord(2)
return nil
}).Find(ctx)
LimitPerRecord(2) 为每条主记录限制预加载的关联数量。many2many 关联不支持 LimitPerRecord。
Raw 与 gen 代码生成
Raw 仍然保留:
gorm.G[User](db).Raw("SELECT * FROM users WHERE name = ? AND age > ?", "jinzhu", 18).Find(ctx)
需要类型安全的原生查询时,官方推荐用代码生成工具:定义 Go interface,用注释写模板 SQL,生成后按下面的方式调用。
query.Query[User](db).GetByID(ctx, 10)
Gen 文档:
为什么复用同一个泛型实例不会条件污染
传统写法里复用 *gorm.DB 容易把上一次的条件带进下一次查询。泛型 API 在机制上规避了这一点:apply(ctx) 内部会先执行
db = db.Session(&Session{NewDB: true, Context: ctx}).getInstance()
然后重放保存的 ops。也就是说,每次操作方法都从一个干净实例开始,条件不会累积:
genericDB := gorm.G[User](db).Where("name = ?", "jinzhu")
user1, err1 := genericDB.Where("age > ?", 10).First(ctx)
user2, err2 := genericDB.Where("age > ?", 20).First(ctx)
第二次查询不会带上第一次的 age > 10。此外,context 直接传给每个操作方法,错误也从操作方法直接返回,不需要 db.WithContext(ctx) 再加 db.Error 两步。
Set:Set-based 写操作
Set(assignments ...clause.Assigner)
v1.30.4 起,Generics API 支持 Set-based Create/Update;v1.31.0 起,Set API 支持关联操作,并启用了条件批量关联更新。
版本与项目信息
- v1.30.0(2025-05-25):Implement Generics API (#7424)
- v1.30.2:新增
DefaultContextTimeout选项 (#7567)、slog 集成 - v1.30.4:Add Set-based Create and Update support to Generics API (#7578)
- v1.31.0:Add association operation support to generics Set API and enable conditional bulk association updates (#7581)
- 当前最新版本:v1.31.2
仓库:(约 40k stars,MIT,模块路径 gorm.io/gorm)
文档:
被移除方法的迁移
Save→ 新建用Create,更新用UpdatesFirstOrCreate→ 先First查询,没有再Create;或使用clause.OnConflict{Columns: ..., DoUpdates: ...}做 Upsert