目录
- 技术概述
- 技术详述
- 遇到的问题和解决过程
- 总结
- 参考文献
技术概述
Gorm框架可以进行多表联合查询,通过多表联合查询可以通过一条sql语句即可完成对数据库多表数据的获取,而不需要执行多条sql语句对数据库进行多次访问,从而加快了数据的处理速度。并且Gorm框架可以根据设计好的Model完成返回数据的封装,并不需要自己对数据进行再次封装。
技术详述
本次团队项目中我们获取评论数据时,不仅需要返回评论的相关信息,还要返回评论的作者的相关信息。如果不用Gorm的多表查询,则需要我们对每一条数据进行一次额外的查询和封装操作。下面是Gorm框架实现多表查询的具体步骤。
1. Model设计
评论和用户是一对多的关系,即一个评论属于一个用户,一个用户可以发布多条评论。
//评论
type Comment struct {
ID int64 `gorm:"column:ID;primaryKey"`
UserID string `gorm:"column:userID"`
Content string `gorm:"column:content"`
CommentNum int64 `gorm:"column:CommentNum"`
TargetPost int64 `gorm:"column:targetPost"`
PublishTime time.Time `gorm:"column:publishTime"`
State int64 `gorm:"column:state"`
Author User `gorm:"foreignKey:UserID"`
}
//用户
type User struct {
ID int64 `gorm:"column:ID;primaryKey"`
Account string
Password string
PhoneNumber string `gorm:"column:phoneNumber"`
NickName string `gorm:"column:nickName"`
Major string
AvatarUrl string `gorm:"column:avatarUrl"`
Sex string
Area string
Year int64
TargetCollege string `gorm:"column:targetCollege"`
TargetMajor string `gorm:"column:targetMajor"`
Slogan string
Balance int64
College string
State int64 `gorm:"column:state"`
RegisterTime time.Time `gorm:"column:registerTime"`
}
可以看到在评论中我添加了User类型的Author字段,还在后面指定了外键是UserID,这样Gorm框架就可以根据UserID进行连表查询,并且不需要额外进行封装工作。
2. SQL语句设计
func SelectSingleCommentByCondition(db *gorm.DB, where map[string]interface{}) (Comment, int64, error) {
var count int64 = 0
var comment Comment
err := db.Joins("Author").Where(where).First(&comment).Count(&count).Error
if count == 0 {
return comment, 0, errors.New("查询的记录不存在")
}
return comment, count, err
}
关键点在于要利用Joins()函数来选择连接查询的表,并且这里的函数参数要根据刚刚的Model设计中的命名来选择,比如在Comment中我们要查询的是Author字段,就传入“Author”。
3. 结果测试
测试函数:
package selectComment
import (
fybDatabase "FybBackend/database"
"FybBackend/routers/v1/backend/token"
"FybBackend/routers/v1/exceptionHandler"
"/gin-gonic/gin"
"/hashicorp/go-multierror"
"gorm.io/gorm"
)
func SelectCommentById(e *gin.Engine, db *gorm.DB) {
e.GET("/v1/backend/comment/searchById", func(context *gin.Context) {
if err := token.JwtVerify(context); err != nil {
context.JSON(403, gin.H{
"code": 403,
"message": err.Error(),
})
return
}
var result *multierror.Error
mp := make(map[string]interface{})
mp[""] = context.DefaultQuery("id", "")
post, _, err1 := fybDatabase.SelectSingleCommentByCondition(db, mp)
result = multierror.Append(result, err1)
code, msg := exceptionHandler.Handle(result)
if code == 200 {
context.JSON(code, gin.H{
"code": code,
"message": "请求成功",
"data": post,
})
} else {
context.JSON(code, gin.H{
"code": code,
"message": msg,
})
}
})
}
利用Postman对接口进行测试,返回结果如下:
可以看到测试函数中没有进行额外的数据封装,返回的结果结构就是按照Model设计中那样返回。
遇到的问题和解决过程
- 问题:sql语句中如何确定是使用left join、right join 还是 inner join
通俗来说,对于表A和表B,left join返回包括表A中的所有记录和表B中联结字段相等的记录;right join返回包括表B中的所有记录和表A中联结字段相等的记录;inner join只返回两个表中联结字段相等的行。下面用一张图来直观的表示:
这里我们要查询的是评论的数据,因此选择left join。那么写的查询函数为什么用的是Joins()函数呢?通过查询Gorm框架的源代码我们可以发现,Joins函数就是使用了left join。
总结
- 经过这次对Gorm框架的多表联合查询的学习,进一步加强了我对Gorm框架的掌握程度,对数据库的学习有了更深的理解。
参考文献
- 参考博客
- left join、right join和join的区别
- gorm 连接查询
- 参考文档