一对多关联查询
# 1 一对多入门
# 1.1 has many介绍
has many
关联就是创建和另一个模型的一对多关系。不同于 has one
,拥有者可以有零或多个关联模型。
例如, 例如每一个用户都拥有多张信用卡,这样就是生活中一个简单的一对多关系。
// 用户有多张信用卡,UserID 是外键
type User struct {
gorm.Model
CreditCards []CreditCard
}
type CreditCard struct {
gorm.Model
Number string
UserID uint // 默认会在 CreditCard 表中生成 UserID 字段作为 与User表关联的外键ID
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 1.2 外键
为了定义一对多关系, 外键是必须存在的,默认外键的名字是 所有者类型的名字加上它的主键 (UserId) 。就像上面的例子,为了定义一个属于 User 的模型,外键就应该为 UserID 。
使用其他的字段名作为外键, 可以通过 foreignkey 来定制它。
type User struct {
gorm.Model
// foreignkey:UserRefer 可以自己指定外键关联字段名为:UserRefer
// 默认外键字段名是 UserId,你也可以自己修改
CreditCards []CreditCard `gorm:"foreignkey:UserRefer"`
}
type CreditCard struct {
gorm.Model
Number string
UserRefer uint
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 1.3 外键关联
GORM 通常使用所有者的主键作为外键的值, 在上面的例子中,它就是 User 的 ID 。
当你分配信用卡给一个用户, GORM 将保存用户 ID 到信用卡表的 UserID 字段中。
你能通过 association_foreignkey 来改变它。
type User struct {
gorm.Model
MemberNumber string
// 默认CreditCard会使用User表的Id作为外键,association_foreignkey:MemberNumber 指定使用 MemberNumber 作为外键关联
CreditCards []CreditCard `gorm:"foreignkey:UserMemberNumber;association_foreignkey:MemberNumber"`
}
type CreditCard struct {
gorm.Model
Number string
UserMemberNumber string
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 2. 创建一对多表
# 2.1 表结构定义
重写外键、外键约束
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
/*
constraint:OnUpdate:CASCADE 【当User表更新,也会同步给CreditCards】 // 外键约束
OnDelete:SET NULL 【当User中数据被删除时,CreditCard关联设置为 NULL,不删除记录】
*/
type User struct {
gorm.Model
Username string `json:"username" gorm:"column:username"`
CreditCards []CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
func main() {
// 0、连接数据库
dsn := "root:1@tcp(127.0.0.1:3306)/test_db?
charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 创建表结构
db.AutoMigrate(User{}, CreditCard{})
// 1、创建一对多
user := User{
Username: "zhangsan",
CreditCards: []CreditCard{
{Number: "0001"},
{Number: "0002"},
},
}
db.Create(&user)
// 2、为已存在用户添加信用卡
u := User{Username: "zhangsan"}
db.First(&u)
//fmt.Println(u.Username)
db.Model(&u).Association("CreditCards").Append([]CreditCard{
{Number: "0003"},
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
创建结果说明
我们没有指定 foreignkey,所以会与 UserID字段自动建立外键关联关系。
# 2.2 一对多 Association
使用 Association 方法, 需要把 User 查询好, 然后根据 User 定义中指定的 AssociationForeignKey 去查找 CreditCard。
package main
import (
"encoding/json"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
/*
constraint:OnUpdate:CASCADE 【当User表更新,也会同步给CreditCards】
OnDelete:SET NULL 【当User中数据被删除时,CreditCard关联设置为 NULL,不删除记录】
*/
type User struct {
gorm.Model
Username string `json:"username" gorm:"column:username"`
CreditCards []CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
func main() {
// 0、连接数据库
dsn := "root:1@tcp(127.0.0.1:3306)/test_db?
charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 1、查找 用户名为 zhangsan 的所有信用卡信息
u := User{Username: "zhangsan"} // Association必须要先查出User才能关联查询对应的CreditCard
db.First(&u)
err := db.Model(&u).Association("CreditCards").Find(&u.CreditCards)
if err != nil {
fmt.Println(err)
}
strUser, _ := json.Marshal(&u)
fmt.Println(string(strUser))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
打印结果如下:
{ "ID":1, "username":"zhangsan", "CreditCards":[ { "ID":1, "Number":"0001", "UserID":1 }, ... ] }
1
2
3
4
5
6
7
8
9
10
11
12
# 2.3 一对多 Preload
使用 Preload 方法, 在查询 User 时先去获取 CreditCard 的记录。
package main
import (
"encoding/json"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
/*
constraint:OnUpdate:CASCADE 【当User表更新,也会同步给CreditCards】
OnDelete:SET NULL 【当User中数据被删除时,CreditCard关联设置为 NULL,不删除记录】
*/
type User struct {
gorm.Model
Username string `json:"username" gorm:"column:username"`
CreditCards []CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
func main() {
// 0、连接数据库
dsn := "root:1@tcp(127.0.0.1:3306)/test_db?
charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 1、预加载: 查找 user 时预加载相关 CreditCards
//users := User{Username: "zhangsan"} // 只查找张三用户的信用卡信息
users := []User{}
db.Preload("CreditCards").Find(&users)
strUser, _ := json.Marshal(&users)
fmt.Println(string(strUser))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
上次更新: 2022/07/11, 00:25:56