1.原生 SQL 和 SQL 生成器
(1).使用原生 sql 删除 user 表中的一条数据
result := models.DB.Exec("delete from user where id=?", 3)
fmt.Println(result.RowsAffected)
(2).使用原生 sql 修改 user 表中的一条数据
result := models.DB.Exec("update user set username=? where id=2", "哈哈")
fmt.Println(result.RowsAffected)
(3).查询 uid=2 的数据
var result models.User
models.DB.Raw("SELECT * FROM user WHERE id = ?", 2).Scan(&result)
fmt.Println(result)
(4).查询 User 表中所有的数据
var result []models.User
models.DB.Raw("SELECT * FROM user").Scan(&result)
fmt.Println(result)
(5).统计 user 表的数量
var count int
row := models.DB.Raw("SELECT count(1) FROM user").Row(&count )
row.Scan(&count)
更多使用方法:https://gorm.io/zh_CN/docs/sql_builder.html
2.Gin 中使用 GORM 实现表关联查询
![](https://i-blog.csdnimg.cn/blog_migrate/de43cfac8c3791e7d40120c1598c481f.png)
(1).一对一
如上图所示,一个文章只有一个分类,article 和 article_cate 之间是 1 对 1 的关系,文章表中的 cate_id 保存着文章分类的 id,如果我们想查询文章的时候同时获取文章分类,就涉及到 1 对 1 的关联查询.
foreignkey 指定当前表的外键、 references 指定关联表中和外键关联的字段
Article.go模型
package models
//文章
type Article struct { // 结构体首字母大写, 和数据库表名对应, 默认访问数据表users, 可以设置访问数据表的方法
Id int `json:"id"`
Title string `json:"title"`
CateId int `json:"cate_id"` // 该键是文章分类的外键, 如果该键是ArticleCateId,那么就会直接和ArticleCate.Id建立关系
State int `json:"state"`
ArticleCate ArticleCate `gorm:"foreignKey:CateId"` // 使用 CateId 作为外键 // 和文章分类建立关系
}
//配置数据库操作的表名称
func (Article) TableName() string {
return "article"
}
ArticleCate.go模型
package models
//文章分类
type ArticleCate struct { // 结构体首字母大写, 和数据库表名对应, 默认访问数据表users, 可以设置访问数据表的方法
Id int `json:"id"` // 主键, 可用于和其他数据表建立关系,
Title string `json:"title"`
State int `json:"state"`
}
//配置数据库操作的表名称
func (ArticleCate) TableName() string {
return "article_cate"
}
查询所有文章以及文章对应的分类信息
func (con ArticleController) Index(c *gin.Context) {
//定义文章结构体切片
articleList := []models.Article{}
//查询所有文章,以及文章的分类Preload
models.DB.Preload("ArticleCate").Where("state = ?", 1).Find(&articleList)
c.JSON(http.StatusOK, gin.H{
"result": articleList,
})
c.JSON(http.StatusOK, gin.H{
"result": articleCateList,
})
}
注意:Preload("ArticleCate")里面的 ArticleCate 为 Article struct 中定义的属性 ArticleCate
返回 JSON 数据
[
{
"id": 1,
"title": "xxx",
"description": 0,
"cate_id": "1",
"state": 1,
"ArticleCate": {
"id": 1,
"title": "国内",
"state": 1
},
...
}
查询所有文章以及文章对应的分类信息 指定条件
func (con ArticleController) Index(c *gin.Context) {
var articleList []models.Article
models.DB.Preload("ArticleCate").Where("id>=?", 4).Find(&articleList)
c.JSON(200, gin.H{
"result": articleList,
})
}
(2).一对多
一对多在实际项目中用的非常多: 比如一个点餐系统:有菜品分类、有菜品。 菜品分类和菜品之间就是一对多的关系; 订单表和订单商品表:订单表和订单商品表之间也是一对多的关系;如上图所示,一个分类下面有很多个文章,article_cate 和 article 之间是一对多的关系,文章表中的 cate_id 保存着文章分类的 id.如果想查询文章分类的时候获取分类下面的文章,这个时候就涉及到一对多的关联查
询,那么ArticleCate.go模型就要修改一下,看下面的代码:
package models
//文章分类
type ArticleCate struct { // 结构体首字母大写, 和数据库表名对应, 默认访问数据表users, 可以设置访问数据表的方法
Id int `json:"id"` // 主键, 可用于和其他数据表建立关系,
Title string `json:"title"`
State int `json:"state"`
//foreignKey: 外键,如果是表名称加上Id,默认也可以不配置,如果不是,则需要通过foreignKey配置外键名称
//references: 主键,默认是Id,如果是Id,默认也可以不配置
Article []Article `gorm:"foreignKey:CateId;references:Id"` // 关联分类的所有文章
}
//配置数据库操作的表名称
func (ArticleCate) TableName() string {
return "article_cate"
}
ArticleController.go控制器代码如下:
func (con ArticleController) Index(c *gin.Context) {
//定义文章分类结构体切片
articleCateList := []models.ArticleCate{}
//查询所有文章分类,以及文章分类对应的所有文章数据
models.DB.Preload("Article").Where("state = ?", 1).Find(&articleCateList)
c.JSON(http.StatusOK, gin.H{
"result": articleCateList,
})
}
返回的json数据如下:
[
{
"id": 1,
"title": "国内",
"state": 1,
"Article": [
{
"id": 1,
"title": "xxx",
"description": 0,
"cate_id": "1",
"state": 1
},
{
"id": 2,
"title": "xxx",
"description": 0,
"cate_id": "1",
"state": 1
},
...
],
},
...
]
更多使用方法:https://gorm.io/zh_CN/docs/has_many.html, https://github.com/jouyouyun/examples/tree/master/gorm/related
(3).多对多
![](https://i-blog.csdnimg.cn/blog_migrate/bf2adb889ddef0628f01433db9315da0.png)
一个学生可以选修多门课程,一门课程可以被多个学生选修,这就是一个典型的多对多的案例,这需要三个相关数据表,一个是学生表(student),保存的是学生基本信息,一个是课程表(lession).保存的是课程相关信息,最后一个是课程-学生关联表(lession_student),保存的是课程-学生选修关系的数据信息,代码如下:
模型代码如下:
Lession.go
package models
// 课程模型
type Lesson struct {
Id int `json:"id"` // 主键, 可用于和其他数据表建立关系,
Name string `json:"name"`
Student []Student `gorm:"many2many:lesson_student;"`
}
//配置数据库操作的表名称
func (Lesson) TableName() string {
return "lesson"
}
Student.go
package models
// 学生模型
type Student struct {
Id int `json:"id"`
Number string `json:"number"`
Password string `json:"password"`
ClassId int `json:"class_id"`
Name string `json:"name"`
Lesson []Lesson `gorm:"many2many:lesson_student;"`
}
//配置数据库操作的表名称
func (Student) TableName() string {
return "student"
}
LessonStudent.go
package models
//课程-学生关系模型
type LessonStudent struct {
LessonId int `json:"lesson_id"`
StudentId int `json:"student_id"`
}
//配置数据库操作的表名称
func (LessonStudent) TableName() string {
return "lesson_student"
}
控制器代码:
package admin
import (
"gindemo/models"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"net/http"
)
//定义一个StudentController结构体,可以实例化结构体访问里面的方法
type StudentController struct {
BaseController // 继承基础控制器
}
//列表
func (con StudentController) Index(c *gin.Context) {
//获取所有学生信息
StudentList := []models.Student{}
models.DB.Find(&StudentList)
c.JSON(http.StatusOK, gin.H{
"获取所有学生信息": StudentList,
})
//获取所有课程信息
LessonList := []models.Lesson{}
models.DB.Find(&LessonList)
c.JSON(http.StatusOK, gin.H{
"获取所有课程信息": LessonList,
})
//查询学生信息的时候,展示学生选修的课程
StudentLessonList := []models.Student{}
models.DB.Preload("Lesson").Find(&StudentLessonList)
c.JSON(http.StatusOK, gin.H{
"查询学生信息的时候,展示学生选修的课程": StudentLessonList,
})
//查询某个学生的选修课程信息
StudentOneList := []models.Student{}
models.DB.Preload("Lesson").Where("name = ?", "张三").Find(&StudentOneList)
c.JSON(http.StatusOK, gin.H{
"查询某个学生的选修课程信息": StudentOneList,
})
//查询课程被哪些学生选修了
LessonStudentList := []models.Lesson{}
models.DB.Preload("Student").Find(&LessonStudentList)
c.JSON(http.StatusOK, gin.H{
"查询课程被哪些学生选修了": LessonStudentList,
})
//查询某个课程被哪些学生选修了
LessonStudentOneList := []models.Lesson{}
models.DB.Preload("Student").Where("name = ?", "计算机网络").Find(&LessonStudentOneList)
c.JSON(http.StatusOK, gin.H{
"查询某个课程被哪些学生选修了": LessonStudentOneList,
})
//查询指定条件
LessonCondition := []models.Lesson{}
models.DB.Preload("Student").Offset(1).Limit(2).Where("name = ?", "计算机网络").Find(&LessonCondition)
c.JSON(http.StatusOK, gin.H{
"查询指定条件": LessonCondition,
})
//查询课程时候,排除某个学生
LessonNot := []models.Lesson{}
//models.DB.Preload("Student", "id != ?", 1).Find(&LessonNot) // id 不等于某个学生
models.DB.Preload("Student", "id not in (1, 2)?").Find(&LessonNot) // id 不等于某些学生
c.JSON(http.StatusOK, gin.H{
"查询课程时候,排除某个学生": LessonNot,
})
//预加载sql:需要引入 gorm.io/gorm 这个包
LessonByStudentOrder := []models.Lesson{}
models.DB.Preload("Student", func(db *gorm.DB) *gorm.DB {
return models.DB.Where("id > 3").Order("student.id DESC")
}).Find(&LessonByStudentOrder)
c.JSON(http.StatusOK, gin.H{
"预加载sql,按学生id降序排列": LessonByStudentOrder,
})
}
注意:
上面的预加载sql操作中,需要引入 gorm.io/gorm 这个包
更多操作,请看:
预加载: https://gorm.io/zh_CN/docs/preload.html
Many To Many: https://gorm.io/zh_CN/docs/many_to_many.html