GORM专题-高级查询

2022/10/6 gosql

🌙 1.Scopes

scopes是GORM中的一种链式调用方式,可以用于在查询中添加条件。它的作用是可以将一些常用的查询条件封装成一个scope,方便在多个地方复用。例如, 通用的分页逻辑:

func Paginate(r *http.Request) func(db *gorm.DB) *gorm.DB {
    return func (db *gorm.DB) *gorm.DB {
        q := r.URL.Query()
        page, _ := stronv.Atoi(q.Get("page"))
        if pge == 0 {
            page = 1
        }
        
        switch {
        case pageSize > 100: 
            pageSize = 100
        case pageSize <= 0: 
            pageSize = 10
        }
        
        offset := (page - 1) * pageSize
        return db.Offset(offset).Limit(pageSize)
    }
}

db.Scope(Paginate(r)).Find(&users)
db.Scope(Paginate(r)).Find(&articles)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

🌙 2.智能选择字段

GORM支持在查询时只选择需要的字段,可以使用Select方法来指定需要选择的字段。例如,我们可以只选择用户的nameid字段:

type User struct {
    ID uint
    Name string
    Age int
    Gender string
    // 假设后面还有很多字段
    ...
}

type APIUser struct {
    ID uint
    Name string
}

// 查询时会自动选择 `id`、`name` 字段
db.Model(&User{}).Limit(10).Find(&APIUser{})
// 相当于:SELECT `id`, `name` FROM `users` LIMIT 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

🌙 3.子查询

  • where 子查询
type User struct {
    ID uint
    Name string
    Age int
    Gender string
}

// 查询年龄大于女性平均年龄的用户
// SELECT * FROM `users` WHERE age > (SELECT AVG(age) FROM `users` WHERE gender = 'female')
var users []User
db.Where("age > ?", db.Table("users").Select("AVG(age)").Where("gender = ?", "female").QueryExpr()).Find(&users)
1
2
3
4
5
6
7
8
9
10
11
  • from子查询
// SELECT * FROM (SELECT `name`, `age` FROM `users`) as u WHERE `age` = 18
db.Table("(?) as u", db.Model(&User{}).Select("name", "age")).Where("age = ?", 18).Find(&User{})

subQuery1 := db.Model(&User{}).Select("name")
subQuery2 := db.Model(&Pet{}).Select("name")
db.Table("(?) as u, (?) as p", subQuery1, subQuery2).Find(&User{})
1
2
3
4
5
6

🌙 4.关联查询

GORM支持多种关联查询,包括一对一、一对多、多对多等。下面将详细介绍这些关联查询的使用方法。

🌙 4.1.一对一关联

一对一关联是指两个表之间的关系是一对一的关系。例如,一个用户只有一个身份证号,一个身份证号也只对应一个用户。在GORM中,我们可以使用hasOne和belongsTo方法来建立一对一关联。

🌙 4.1.1 hasOne

hasOne方法用于建立一个从当前模型到另一个模型的一对一关联。例如,我们可以将User和IDCard模型建立一对一关联:

type User struct {
    ID uint
    Name string
    Age int
    Gender string
    IDCard IDCard
}

type IDCard struct {
    ID uint
    Number string
    UserID uint
}

// 建立一对一关联
db.Model(&User{}).HasOne(&IDCard{})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

上面的代码中,我们使用HasOne方法将User和IDCard模型建立了一对一关联。这样,在查询User模型时,GORM会自动关联查询IDCard模型,并将查询结果赋值给User模型的IDCard字段。

🌙 4.1.2 belongsTo

belongsTo方法用于建立一个从另一个模型到当前模型的一对一关联。例如,我们可以将IDCard和User模型建立一对一关联:

type User struct {
    ID uint
    Name string
    Age int
    Gender string
    IDCard IDCard
}

type IDCard struct {
    ID uint
    Number string
    UserID uint
    User User
}

// 建立一对一关联
db.Model(&IDCard{}).BelongsTo(&User{})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

🌙 4.2.一对多关联

一对多关联是指一个模型对应多个另一个模型。例如,一个用户可以有多篇文章,一篇文章只能对应一个用户。在GORM中,我们可以使用hasMany和belongsTo方法来建立一对多关联。

🌙 4.2.1 hasMany

hasMany方法用于建立一个从当前模型到另一个模型的一对多关联。例如,我们可以将User和Article模型建立一对多关联:

type User struct {
    ID uint
    Name string
    Age int
    Gender string
    Articles []Article
}

type Article struct {
    ID uint
    Title string
    Content string
    UserID uint
}

// 建立一对多关联
db.Model(&User{}).HasMany(&Article{})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

上面的代码中,我们使用HasMany方法将User和Article模型建立了一对多关联。这样,在查询User模型时,GORM会自动关联查询Article模型,并将查询结果赋值给User模型的Articles字段。

🌙 4.2.2 belongsTo

belongsTo方法用于建立一个从另一个模型到当前模型的一对多关联。例如,我们可以将Article和User模型建立一对多关联:

type User struct {
    ID uint
    Name string
    Age int
    Gender string
    Articles []Article
}

type Article struct {
    ID uint
    Title string
    Content string
    UserID uint
    User User
}

// 建立一对多关联
db.Model(&Article{}).BelongsTo(&User{})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

上面的代码中,我们使用BelongsTo方法将Article和User模型建立了一对多关联。这样,在查询Article模型时,GORM会自动关联查询User模型,并将查询结果赋值给Article模型的User字段。

🌙 4.3.多对多关联

多对多关联是指两个模型之间的关系是多对多的关系。例如,一个用户可以有多个角色,一个角色也可以对应多个用户。在GORM中,我们可以使用many2many方法来建立多对多关联。

type User struct {
    ID uint
    Name string
    Age int
    Gender string
    Roles []Role `gorm:"many2many:user_roles;"`
}

type Role struct {
    ID uint
    Name string
    Users []User `gorm:"many2many:user_roles;"`
}

// 建立多对多关联
db.Model(&User{}).Association("Roles").Append(&Role{Name: "admin"})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

上面的代码中,我们使用many2many方法将User和Role模型建立了多对多关联。这样,在查询User模型时,GORM会自动关联查询Role模型,并将查询结果赋值给User模型的Roles字段。

在添加关联时,我们可以使用Association方法来添加关联。例如,我们可以将一个用户和一个角色关联起来:

db.Model(&User{}).Association("Roles").Append(&Role{Name: "admin"})

1
2

上面的代码中,我们使用Association方法将一个用户和一个角色关联起来。这样,在查询User模型时,GORM会自动关联查询Role模型,并将查询结果赋值给User模型的Roles字段。