Gorm框架-表关系
大约 4 分钟
表关系
一对一
一对一关系比较少,一般用于表的扩展
例如一张用户表,有很多字段
那么就可以把它拆分为两张表,常用的字段放主表,不常用的字段放详情表
搭建表结构
type User struct {
ID uint
Name string
Age int
Gender bool
UserInfo UserInfo // 通过UserInfo可以拿到用户详情信息
}
type UserInfo struct {
UserID uint // 外键
ID uint
Addr string
Like string
}
func main(){
DB.AutoMigrate(&User{}, UserInfo{})
}
添加记录
添加用户,自动添加用户详情
DB.Create(&User{
Name: "张三",
Age: 21,
Gender: true,
UserInfo: UserInfo{
Addr: "河南省",
Like: "编程",
},
})
添加用户详情,关联已有用户
DB.Create(&UserInfo{
UserID: 2,
Addr: "濮阳市",
Like: "吃饭",
})
直接传递用户对象
type User struct {
ID uint
Name string
Age int
Gender bool
UserInfo UserInfo // 通过UserInfo可以拿到用户详情信息
}
type UserInfo struct {
User *User // 要改成指针,不然就嵌套引用了
UserID uint // 外键
ID uint
Addr string
Like string
}
var user User
DB.Take(&user, 2)
DB.Create(&UserInfo{
User: &user,
Addr: "濮阳市",
Like: "吃饭",
})
查询记录
一般是通过主表查附表
var user User
DB.Preload("UserInfo").Take(&user)
fmt.Println(user)
一对多
我们以用户和文章为例
一个用户可以发布多篇文章,一篇文章属于一个用户
搭建表结构
type User struct {
ID uint `gorm:"size:4"`
Name string `gorm:"size:8"`
Articles []Article // 用户拥有的文章列表
}
type Article struct {
ID uint `gorm:"size:4"`
Title string `gorm:"size:16"`
UserID uint `gorm:"size:4"` // 属于 这里的类型要和引用的外键类型一致,包括大小
User User // 属于
}
关于外键命名,外键名称就是关联表名+ID,类型是uint
重写外键关联
type User struct {
ID uint `gorm:"size:4"`
Name string `gorm:"size:8"`
Articles []Article `gorm:"foreignKey:UID"` // 用户拥有的文章列表
}
type Article struct {
ID uint `gorm:"size:4"`
Title string `gorm:"size:16"`
UID uint // 属于
User User `gorm:"foreignKey:UID"` // 属于
}
添加记录
创建用户,并且创建文章
a1 := Article{Title: "java"}
a2 := Article{Title: "golang"}
user := User{Name: "张三", Articles: []Article{a1, a2}}
DB.Create(&user) // 数据库里文章表新加两条记录,用户表新加一条记录,并已关联
创建文章,关联已有用户
a1 := Article{Title: "golang零基础入门", UserID: 1}
DB.Create(&a1)
// 或者
var user User
DB.Take(&user, 1)
DB.Create(&Article{Title: "python零基础入门", User: user})
外键添加
给已有用户绑定已有文章
var user User
DB.Take(&user, 2)
var article Article
DB.Take(&article, 5)
user.Articles = []Article{article}
DB.Save(&user)
// 也可以用Append方法
var user User
DB.Take(&user, 2)
var article Article
DB.Take(&article, 5)
DB.Model(&user).Association("Articles").Append(&article)
给已有文章绑定已有用户
var article Article
DB.Take(&article, 5)
article.UserID = 2
DB.Save(&article)
// 也可以用Append方法
var user User
DB.Take(&user, 2)
var article Article
DB.Take(&article, 5)
DB.Model(&article).Association("User").Append(&user)
查询记录
查询用户,显示用户的文章列表
var user User
DB.Take(&user, 1)
fmt.Println(user) // 不显示文章列表
需要使用预加载
var user User
DB.Preload("Articles").Take(&user, 1)
fmt.Println(user) // 显示文章列表
预加载的名字就是外键关联的属性名
查询文章,显示文章用户的信息
同样的,使用预加载
var article Article
DB.Preload("User").Take(&article, 1)
fmt.Println(article)
嵌套预加载
查询文章,显示用户,并且显示用户关联的所有文章,这就得用到嵌套预加载了
var article Article
DB.Preload("User.Articles").Take(&article, 1)
fmt.Println(article)
带条件的预加载
var user User
DB.Preload("Articles", "id = ?", 1).Take(&user, 1)
fmt.Println(user)
自定义预加载
var user User
DB.Preload("Articles", func(db *gorm.DB) *gorm.DB {
return db.Where("id in ?", []int{1, 2})
}).Take(&user, 1)
fmt.Println(user)
删除记录
级联删除,删除用户,与用户关联的文章也会删除
var user User
DB.Take(&user, 1)
DB.Select("Articles").Delete(&user)
清除外键关系,删除用户,与用户关联的文章设置为null
var user User
DB.Preload("Articles").Take(&user, 2)
DB.Model(&user).Association("Articles").Delete(&user.Articles)
多对多
多对多关系,需要用第三张表存储两张表的关系
搭建表结构
type Tag struct {
ID uint
Name string
Articles []Article `gorm:"many2many:article_tags;"` // 用于反向引用
}
type Article struct {
ID uint
Title string
Tags []Tag `gorm:"many2many:article_tags;"`
}
添加记录
添加文章,并创建标签
DB.Create(&Article{
Title: "python基础课程",
Tags: []Tag{
{Name: "python"},
{Name: "基础课程"},
},
})
添加文章,选择标签
var tags []Tag
DB.Find(&tags, "name = ?", "基础课程")
DB.Create(&Article{
Title: "golang基础",
Tags: tags,
})
查询记录
查询文章,显示文章的标签列表
var article Article
DB.Preload("Tags").Take(&article, 1)
fmt.Println(article)
查询标签,显示文章列表
var tag Tag
DB.Preload("Articles").Take(&tag, 2)
fmt.Println(tag)
更新记录
移除文章的标签
var article Article
DB.Preload("Tags").Take(&article, 1)
DB.Model(&article).Association("Tags").Delete(article.Tags)
fmt.Println(article)
更新文章的标签
var article Article
var tags []Tag
DB.Find(&tags, []int{2, 6, 7})
DB.Preload("Tags").Take(&article, 2)
DB.Model(&article).Association("Tags").Replace(tags)
fmt.Println(article)