605 字
3 分钟
关联关系

GORM 关联关系#

常见关系#

关系示例外键通常位于
Belongs ToOrder belongs to Userorders.user_id
Has OneUser has one Profileprofiles.user_id
Has ManyUser has many Orderorders.user_id
Many To ManyUser belongs to many Role中间表,如 user_roles

模型示例#

type User struct {
ID uint
Name string
Profile Profile
Orders []Order
Roles []Role `gorm:"many2many:user_roles;"`
}
type Profile struct {
ID uint
UserID uint
Bio string
}
type Order struct {
ID uint
UserID uint
User User
Amount int64
}
type Role struct {
ID uint
Name string `gorm:"uniqueIndex"`
}

明确写出 UserID 和 User,比完全依赖推断更容易阅读和排查。

Preload 预加载#

var users []User
err := db.Preload("Profile").
Preload("Orders").
Where("status = ?", "active").
Find(&users).Error

预加载通常会额外执行查询,避免了循环中逐条加载关联记录,但仍要关注返回数据量。可以限制预加载字段或条件:

db.Preload("Orders", func(tx *gorm.DB) *gorm.DB {
return tx.Select("id", "user_id", "amount").
Where("amount > ?", 0).
Order("id DESC")
}).Find(&users)

嵌套预加载:

db.Preload("Orders.Items.Product").Find(&users)

嵌套层级越深,越需要确认查询数量、数据量和 API 返回结构。

Joins 与 Join Preload#

需要按关联表字段筛选、排序或只返回扁平结果时,可以使用 Joins:

var orders []Order
db.Joins("User").
Where("users.name = ?", "Alice").
Find(&orders)

Preload 主要用于加载关联对象;Joins 主要用于把关联表加入当前 SQL。二者生成的结果结构和 SQL 形态不同,不能只按“哪个查询次数少”机械选择。

创建关联#

user := User{
Name: "Alice",
Profile: Profile{Bio: "Go developer"},
Orders: []Order{{Amount: 100}},
}
if err := db.Create(&user).Error; err != nil {
return err
}

不希望自动保存某个关联时:

db.Omit("Profile").Create(&user)
db.Omit("Roles").Create(&user)

关联写入涉及多条 SQL,关键业务应放在显式事务中,不要只依赖调用方“通常会成功”。

Association Mode#

需要单独管理关联时:

db.Model(&user).Association("Orders").Append(&order)
db.Model(&user).Association("Orders").Delete(&order)
count := db.Model(&user).Association("Orders").Count()

使用前确认主键已经存在,且关联名称与模型字段一致。

关联删除策略#

删除用户时,关联订单是级联删除、软删除、保留还是转移,需要由业务明确决定。数据库外键的 OnDelete 行为和 GORM 的 Select 删除行为不是同一层概念,迁移和测试必须覆盖。

常见坑#

  • 忘记 Preload,导致返回 JSON 中关联为空。
  • 在循环中逐条查询关联,形成 N+1。
  • Many2Many 中间表的唯一约束缺失,重复关联难以发现。
  • 用 Preload 加载巨大集合,导致内存和响应体爆炸。
  • 关联字段和外键命名不一致却没有显式 foreignKey、references 标签。

官方资料#

关联关系
https://shirone.mysqil.com/posts/gorm/关联关系/
作者
HikariTish
发布于
2026-07-30
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取