关联
建立关系模型
关联 是 CoddyKit 上的免费 Go Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Go Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Go Academy 课程共包含 4 节课。
关系建模
GORM 的关联会将表之间的关系映射到结构体字段上。四种关联类型是一对一、一对多、属于和多对多。
- 将外键表示为结构体字段
- 自动加载相关数据
- 同时创建相关记录
一对多
一个用户可以拥有多篇文章。父记录持有子记录切片,子记录持有指向父记录的外键。
type User struct {
gorm.Model
Name string
Posts []Post
}
type Post struct {
gorm.Model
Title string
UserID uint
}属于
从子记录的角度看,一篇文章属于一个用户。添加一个 User 字段以及 UserID 外键即可表达这种关系。
type Post struct {
gorm.Model
Title string
UserID uint
User User
}一对一
一对一关联类似于一对多关联,但只有一条相关记录,例如一个用户拥有一个个人资料。子记录持有外键。
type User struct {
gorm.Model
Profile Profile
}
type Profile struct {
gorm.Model
UserID uint
Bio string
}多对多
用户和角色通过连接表形成多对多关系。many2many 标签用于命名连接表,写在 Roles 字段后的反引号中,形式为 gorm:"many2many:user_roles;"。
type User struct {
gorm.Model
// Roles field tag: gorm:"many2many:user_roles;"
Roles []Role
}
type Role struct {
gorm.Model
Name string
}Preload
默认情况下不会加载相关数据。Preload 会让 GORM 通过单独的查询获取关联数据,从而避免手动执行额外的查找。
var user User
db.Preload("Posts").First(&user, 1)
fmt.Println(len(user.Posts))嵌套 Preload
您可以使用点号路径跨多个层级进行预加载,在一次调用链中加载用户的文章以及每篇文章的评论。
db.Preload("Posts.Comments").First(&user, 1)可运行的关联模拟
GORM 需要数据库,因此这个可运行示例使用内存切片模拟一对多关系和预加载。
package main
import "fmt"
type Post struct {
ID int
UserID int
Title string
}
type User struct {
ID int
Name string
Posts []Post
}
func preload(u *User, all []Post) {
for _, p := range all {
if p.UserID == u.ID {
u.Posts = append(u.Posts, p)
}
}
}
func main() {
u := User{ID: 1, Name: "Ada"}
all := []Post{{1, 1, "Hello"}, {2, 1, "World"}, {3, 2, "Other"}}
preload(&u, all)
fmt.Printf("%s has %d posts\n", u.Name, len(u.Posts))
}使用关联创建
如果在调用 Create 前设置切片字段,GORM 就会同时插入父记录及其子记录,并自动连接外键。
user := User{Name: "Ada", Posts: []Post{{Title: "Hi"}}}
db.Create(&user)N+1 问题
遍历父记录并在每次迭代中查询子记录,会导致每个父记录执行一次查询,这就是 N+1 问题。Preload 会将相关数据的获取合并到一次额外查询中,从而解决这个问题。
关联模式
Association API 可以追加、替换、删除或清空相关记录,而无需手动处理外键,例如 db.Model(&user).Association("Posts").Append(&post)。
快速检查
请测试您对关联的了解。
总结
您已经学会了关联:
- 使用一对一、一对多、属于和多对多表示模型关系
- 外键是 UserID 这样的结构体字段
- Preload 会加载关联并避免 N+1 问题
- 创建带有子记录的父记录时会连接外键
- 关联模式可以追加、替换或清空关系
常见问题解答
「关联」课时是免费的吗?
是的 — 「关联」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Go Academy 课程的其余内容,请升级到 CoddyKit PRO。 Go Academy 课程共包含 4 节课。
「关联」这节课中我会学到什么?
建立关系模型 你通过在浏览器中直接运行的动手代码来练习 Go Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Go Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Go Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「关联」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Go Academy 课中编写并运行代码吗?
能。每节 Go Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。