GO常用orm框架之gorm学习笔记(3)| 青训营笔记

263 阅读3分钟

[ go 与 golang | 青训营笔记]

这是我参与「第五届青训营 」伴学笔记创作活动的第 15 天, 在学习了go的相关基础知识以后,可以说是初步的了解了go,接下来,我们将步入全新的环节,今天我们学习go的一个常用orm框架gorm

5.高级查询

重新构造一些数据用于查询

func main(){
  var studentList []Student
  DB.Find(&studentList).Delete(&studentList)
  studentList = []Student{
    {ID: 1, Name: "李元芳", Age: 32, Email: PtrString("lyf@yf.com"), Gender: true},
    {ID: 2, Name: "张武", Age: 18, Email: PtrString("zhangwu@lly.cn"), Gender: true},
    {ID: 3, Name: "枫枫", Age: 23, Email: PtrString("ff@yahoo.com"), Gender: true},
    {ID: 4, Name: "刘大", Age: 54, Email: PtrString("liuda@qq.com"), Gender: true},
    {ID: 5, Name: "李武", Age: 23, Email: PtrString("liwu@lly.cn"), Gender: true},
    {ID: 6, Name: "李琦", Age: 14, Email: PtrString("liqi@lly.cn"), Gender: false},
    {ID: 7, Name: "晓梅", Age: 25, Email: PtrString("xiaomeo@sl.com"), Gender: false},
    {ID: 8, Name: "如燕", Age: 26, Email: PtrString("ruyan@yf.com"), Gender: false},
    {ID: 9, Name: "魔灵", Age: 21, Email: PtrString("moling@sl.com"), Gender: true},
  }
  DB.Create(&studentList)
}

func PtrString(email string) *string {
  return &email
}

Where

等价于sql语句中的where

var users []Student
// 查询用户名是枫枫的
DB.Where("name = ?", "枫枫").Find(&users)
fmt.Println(users)
// 查询用户名不是枫枫的
DB.Where("name <> ?", "枫枫").Find(&users)
fmt.Println(users)
// 查询用户名包含 如燕,李元芳的
DB.Where("name in ?", []string{"如燕", "李元芳"}).Find(&users)
fmt.Println(users)
// 查询姓李的
DB.Where("name like ?", "李%").Find(&users)
fmt.Println(users)
// 查询年龄大于23,是qq邮箱的
DB.Where("age > ? and email like ?", "23", "%@qq.com").Find(&users)
fmt.Println(users)
// 查询是qq邮箱的,或者是女的
DB.Where("gender = ? or email like ?", false, "%@qq.com").Find(&users)
fmt.Println(users)

使用结构体查询

使用结构体查询,会过滤零值

并且结构体中的条件都是and关系

// 会过滤零值
DB.Where(&Student{Name: "李元芳", Age: 0}).Find(&users)
fmt.Println(users)

使用map查询

不会过滤零值

DB.Where(map[string]any{"name": "李元芳", "age": 0}).Find(&users)
// SELECT * FROM `students` WHERE `age` = 0 AND `name` = '李元芳'
fmt.Println(users)

Not条件

和where中的not等价

// 排除年龄大于23的
DB.Not("age > 23").Find(&users)
fmt.Println(users)

Or条件

和where中的or等价

DB.Or("gender = ?", false).Or(" email like ?", "%@qq.com").Find(&users)
fmt.Println(users)

Select 选择字段

DB.Select("name", "age").Find(&users)
fmt.Println(users)
// 没有被选中,会被赋零值

可以使用扫描Scan,将选择的字段存入另一个结构体中

type User struct {
  Name string
  Age  int
}
var students []Student
var users []User
DB.Select("name", "age").Find(&students).Scan(&users)
fmt.Println(users)

这样写也是可以的,不过最终会查询两次,还是不这样写

SELECT `name`,`age` FROM `students`
SELECT `name`,`age` FROM `students`

这样写就只查询一次了

type User struct {
  Name string
  Age  int
}
var users []User
DB.Model(&Student{}).Select("name", "age").Scan(&users)
fmt.Println(users)

还可以这样

var users []User
DB.Table("students").Select("name", "age").Scan(&users)
fmt.Println(users)

Scan是根据column列名进行扫描的

type User struct {
  Name123 string `gorm:"column:name"`
  Age     int
}
var users []User
DB.Table("students").Select("name", "age").Scan(&users)
fmt.Println(users)

排序

根据年龄倒序

var users []Student
DB.Order("age desc").Find(&users)
fmt.Println(users)
// desc    降序
// asc     升序

注意order的顺序

分页查询

var users []Student
// 一页两条,第1页
DB.Limit(2).Offset(0).Find(&users)
fmt.Println(users)
// 第2页
DB.Limit(2).Offset(2).Find(&users)
fmt.Println(users)
// 第3页
DB.Limit(2).Offset(4).Find(&users)
fmt.Println(users)

通用写法

var users []Student
// 一页多少条
limit := 2
// 第几页
page := 1
offset := (page - 1) * limit
DB.Limit(limit).Offset(offset).Find(&users)
fmt.Println(users)

去重

var ageList []int
DB.Table("students").Select("age").Distinct("age").Scan(&ageList)
fmt.Println(ageList)

或者

DB.Table("students").Select("distinct age").Scan(&ageList)

分组查询

var ageList []int
// 查询男生的个数和女生的个数
DB.Table("students").Select("count(id)").Group("gender").Scan(&ageList)
fmt.Println(ageList)

有个问题,哪一个是男生个数,那个是女生个数

所以我们应该精确一点

type AggeGroup struct {
  Gender int
  Count  int `gorm:"column:count(id)"`
}

var agge []AggeGroup
// 查询男生的个数和女生的个数
DB.Table("students").Select("count(id)", "gender").Group("gender").Scan(&agge)
fmt.Println(agge)

如何再精确一点,具体的男生名字,女生名字

type AggeGroup struct {
  Gender int
  Count  int    `gorm:"column:count(id)"`
  Name   string `gorm:"column:group_concat(name)"`
}

var agge []AggeGroup
// 查询男生的个数和女生的个数
DB.Table("students").Select("count(id)", "gender", "group_concat(name)").Group("gender").Scan(&agge)
fmt.Println(agge)

总之,使用gorm不会让你忘记原生sql的编写

这一点我还是很喜欢的

执行原生sql

type AggeGroup struct {
  Gender int
  Count  int    `gorm:"column:count(id)"`
  Name   string `gorm:"column:group_concat(name)"`
}

var agge []AggeGroup
DB.Raw(`SELECT count(id), gender, group_concat(name) FROM students GROUP BY gender`).Scan(&agge)

fmt.Println(agge)