tonglin0325的个人主页

go学习笔记——gorm

gen是gorm官方推出的一个GORM代码生成工具

官方文档:https://gorm.io/zh_CN/gen/

1.使用gen框架生成model和dao#

安装gorm gen

1
2
go get -u gorm.io/gen

假设有如下用户表

1
2
3
4
5
6
7
8
CREATE TABLE user
(
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(128) NOT NULL COMMENT '用户名',
`email` varchar(128) NOT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

在cmd目录下创建gen/generate.go文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package main

import (
"fmt"

"gorm.io/driver/mysql"
"gorm.io/gen"
"gorm.io/gorm"
)

const MySQLDSN = "root:123456@tcp(127.0.0.1:55000)/default?charset=utf8mb4&parseTime=True"

func connectDB(dsn string) *gorm.DB {
db, err := gorm.Open(mysql.Open(dsn))
if err != nil {
panic(fmt.Errorf("connect mysql fail: %w", err))
}
return db
}

func main() {
// 指定生成代码的具体相对目录(相对当前文件),默认为:./query
// 默认生成需要使用WithContext之后才可以查询的代码,但可以通过设置gen.WithoutContext禁用该模式
g := gen.NewGenerator(gen.Config{
// 默认会在 OutPath 目录生成CRUD代码,并且同目录下生成 model 包
// 所以OutPath最终package不能设置为model,在有数据库表同步的情况下会产生冲突
// 若一定要使用可以通过ModelPkgPath单独指定model package的名称
OutPath: "./internal/query",
ModelPkgPath: "./internal/model",

// gen.WithoutContext:禁用WithContext模式
// gen.WithDefaultQuery:生成一个全局Query对象Q
// gen.WithQueryInterface:生成Query接口
Mode: gen.WithoutContext | gen.WithDefaultQuery | gen.WithQueryInterface,
})

// 通常复用项目中已有的SQL连接配置db(*gorm.DB)
// 非必需,但如果需要复用连接时的gorm.Config或需要连接数据库同步表信息则必须设置
g.UseDB(connectDB(MySQLDSN))

// 从连接的数据库为所有表生成Model结构体和CRUD代码
g.ApplyBasic(g.GenerateAllTable()...)
// 也可以手动指定需要生成代码的数据表
g.ApplyBasic(g.GenerateModel("user"))

// 执行并生成代码
g.Execute()
}

运行generate.go,将会生成model和dao文件

2.gorm框架CRUD#

1.insert#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func init() {
SetDefault(database.DB)
}

func Test_userDo_Create(t *testing.T) {
user := model.User{
Username: "test",
Email: "test@test",
}
err := User.Create(&user)
if err != nil {
fmt.Println("create user fail")
}
}

2.delete#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func Test_userDo_Delete(t *testing.T) {
/*
user := model.User{
ID: 1,
}
result, err := User.Delete(&user)
*/
result, err := User.Where(User.ID.Eq(2)).Delete()
if err != nil {
fmt.Println("delete user fail")
}
fmt.Println(result)
}

3.update#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func Test_userDo_Update(t *testing.T) {
/*
user := model.User{
ID: 2,
Username: "test2",
Email: "test2@test",
}
result, err := User.Updates(&user)
*/
result, err := User.
Where(User.ID.Eq(2)).
Update(User.Username, "test22")

if err != nil {
fmt.Println("update user fail")
}
fmt.Println(result.RowsAffected)
}

4.select#

1
2
3
4
5
6
7
8
9
func Test_userDo_Scan(t *testing.T) {
user := model.User{}
err := User.Where(User.ID.Eq(2)).Scan(&user)
if err != nil {
fmt.Println("scan user fail")
}
fmt.Println(user)
}

参考:GORM Gen使用指南

5.分页#

使用gorm的scopes

 

3.gorm框架自定义SQL#

gorm还支持编写sql模板,来添加自定义sql的函数逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package model

import "gorm.io/gen"

type Filter interface {
// FilterWithColumn SELECT * FROM @@table WHERE @@column=@value
FilterWithColumn(column string, value string) ([]*gen.T, error)

// FilterWithObject
//
// SELECT * FROM @@table where id > 0
// {{if user != nil}}
// {{if user.ID > 0}}
// AND id = @user.ID
// {{else if user.Username != ""}}
// AND username=@user.Username
// {{else if user.Email != ""}}
// AND email=@user.Email
// {{end}}
// {{end}}
FilterWithObject(user *gen.T) ([]*gen.T, error)
}

然后在generate.go文件中添加

1
2
g.ApplyInterface(func(model.Filter) {}, g.GenerateModel("user"))

使用自定义SQL生成的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
func Test_userDo_FilterWithColumn(t *testing.T) {
result, err := User.FilterWithColumn("username", "test")
if err != nil {
fmt.Println("filter user fail")
}
for _, each := range result {
fmt.Println(each)
}
}

func Test_userDo_FilterWithObject(t *testing.T) {
user := model.User{
ID: 3,
Username: "test2",
Email: "test2@test",
}
result, err := User.FilterWithObject(&user)
if err != nil {
fmt.Println("filter user fail")
}
for _, each := range result {
fmt.Println(each)
}
}

其中FilterWithObject函数的User对象的ID不为空,且大于的时候,执行的SQL如下

1
2
SELECT * FROM user where id > 0 AND id = 3 

ID为空的时候,执行的SQL如下

1
2
SELECT * FROM user where id > 0 AND username='test2' 

ID和Username都为空的时候,执行的SQL如下

1
2
SELECT * FROM user where id > 0 AND email='test2@test' 

参考:GORM Gen使用指南