Gorm关联模式使用总结

Gorm的一些关联使用

最近在学习gin,顺便重构一下项目中的面试系统的一部分来加深对go的学习

gorm是go的一个持久层框架,和java springboot jpa虽然同样是orm框架,但使用上还是有很大区别,没有看教程前还是踩了不少坑,为此开一篇博客来记录一下(持续更新)

1.数据表

一共三张表,面试学生表,面试时间表,面试部门

一个学生对应一个面试时间(一对一关联)

一个面试部门对应多个学生(多对一关联)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
type Student struct{
gorm.Model
StudentName string
//一对一关联面试时间表
StudentTime StudentTime
//对应面试部门的外键,默认为字段名+ID,如果要更改需要加标签(详见官方文档)
DepartmentID uint
}
type StudentTime struct{
gorm.Model
Time string
//对应学生表中的外键
StudentID uint

}
type Department struct{
gorm.Model
DepartmentName string
//学生们
Students []Student
}

2.方法

(1)增

首先要把面试时间定义出来

1
2
3
time := StudentTime{
Time:"2021-5-21",
}

然后定义学生

1
2
3
4
5
student := Student{
StudentName:"fyf",
//此处的time是上面定义的结构体
StudentTime: time,
}

最后在数据库添加记录

1
2
//只需要student即可,studentTime会自动“关联创建“
db.Create(&student)

结果是:

在Student表中创建了一条学生记录,在StudentTime表中也创建了一条时间记录,时间记录的外键StudentID会自动关联到相应的学生记录

创建部门也一样,会自动关联

(2)查询

一开始,用常规的条件查询方法

1
2
3
var user Student

global.GVA_DB.Where("student_name = ?","fyf").Find(&user)

结果和我想的不一样,查询的返回数据中,StudentTime字段是空的

原因是因为Gorm中需要手动进行关联查询,官方叫“预加载”

1
global.GVA_DB.Preload("StudentTime").Where("student_name = ?","fyf").Find(&user)

这样子查询的数据中,StudentTime才有数据

意思是,当一个结构体中有关联结构体的时候,如果要查询这个子结构体,就需要用到预加载

如果这个子结构体还有子结构体,则只需在.后加上名字即可

例如,我在这里查一个部门下的学生

1
2
3
4
5
var department Department

global.GVA_DB.
Preload("Students").
Preload("Students.StudentTime").Where("id = ?",1).Find(&department)

即可查询到这个部门下的学生的面试时间

(3)改

比如说,我要在一个面试部门,插入一个学生

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//同样先定义一个时间,学生
time := StudentTime{
Time:"2021-5-21",
}
student := Student{
StudentName:"fyf",
StudentTime: time,
}
//先找到ID为1的面试部门
var depart Depart
global.GVA_DB.Where("id = ?",1).Find(&depart)
//获得这个部门下面试学生的切片,并且添加数据
students = append(depart.Students,student)
//将切片重新复制给结构体
depart.Students = students
//保存数据库
global.GVA_DB.Save(depart)