07.GORMgen
- 官方文档:https://gorm.io/zh_CN/gen/create.html
# 01.安装mysql
# 1、安装mysql
# 拉取 MySQL 镜像
docker pull mysql
# 运行 MySQL 容器
docker run --name mysql-server -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql
# 安装mysql客户端
brew install mysql-client
vi .zshrc 或 .bash_profile
export PATH=$PATH:/usr/local/opt/mysql-client/bin/mysql
source .zshrc
# 连接到 MySQL 服务器
mysql -h 127.0.0.1 -P 3306 -u root -p123456
# 启停命令
docker stop mysql-server
docker rm mysql-server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 2、创建数据库和表
create database test charset utf8;
use test;
CREATE TABLE book
(
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`title` varchar(128) NOT NULL COMMENT '书籍名称',
`author` varchar(128) NOT NULL COMMENT '作者',
`price` int NOT NULL DEFAULT '0' COMMENT '价格',
`publish_date` datetime COMMENT '出版日期',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='书籍表';
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 02.Gen基本使用
# 1、gen_demo/cmd/gen/generate.go
- 配置即代码,我们通常会在项目的
cmd
目录下定义好Gen框架生成代码的配置。 - 例如,我们的项目名称为
gen_demo
,那么我们就在gen_demo/cmd/gen/generate.go
文件。
package main
// gorm gen configure
import (
"fmt"
"gen_demo/dal/model"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gen"
)
const MySQLDSN = "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True"
func connectDB(dsn string) *gorm.DB {
db, err := gorm.Open(mysql.Open(dsn))
if err != nil {
panic(fmt.Errorf("connect db 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: "../../dal/query",
/* ModelPkgPath: "dal/model"*/
// gen.WithoutContext:禁用WithContext模式
// gen.WithDefaultQuery:生成一个全局Query对象Q
// gen.WithQueryInterface:生成Query接口
Mode: gen.WithDefaultQuery | gen.WithQueryInterface,
})
// 通常复用项目中已有的SQL连接配置db(*gorm.DB)
// 非必需,但如果需要复用连接时的gorm.Config或需要连接数据库同步表信息则必须设置
g.UseDB(connectDB(MySQLDSN))
// 从连接的数据库为所有表生成Model结构体和CRUD代码
// 也可以手动指定需要生成代码的数据表
g.ApplyBasic(g.GenerateAllTable()...)
// 执行并生成代码
g.Execute()
}
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
50
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
50
- 生成代码
cd cmd/gen
go run generate.go
1
2
2
- 上述命令会在项目目录下生成
dal
目录,其中dal/query
中是CRUD代码,dal/model
下则是生成Model结构体。
├── cmd
│ └── gen
│ └── generate.go
├── dal
│ ├── model
│ │ └── book.gen.go
│ └── query
│ ├── book.gen.go
│ └── gen.go
├── go.mod
├── go.sum
└── main.go
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 2、gen_demo/dal/db.go
- 初始化数据库连接
package dal
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var DB *gorm.DB
func ConnectDB(dsn string) *gorm.DB {
db, err := gorm.Open(mysql.Open(dsn))
if err != nil {
panic(fmt.Errorf("connect db fail: %w", err))
}
return db
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 3、main.go
package main
import (
"context"
"fmt"
"gen_demo/dal"
"gen_demo/dal/model"
"gen_demo/dal/query"
"time"
)
// gen demo
// MySQLDSN MySQL data source name
const MySQLDSN = "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True"
func init() {
dal.DB = dal.ConnectDB(MySQLDSN).Debug()
}
func main() {
// 设置默认DB对象
query.SetDefault(dal.DB)
//Create()
//Query()
//GetDefine()
//GetFilter()
GetSearch()
}
func Create() {
// 创建
b1 := model.Book{
Title: "《七米的Go语言之路》",
Author: "七米",
PublishDate: time.Date(2023, 11, 15, 0, 0, 0, 0, time.UTC),
Price: 100,
}
err := query.Book.WithContext(context.Background()).Create(&b1)
if err != nil {
fmt.Printf("create book fail, err:%v\n", err)
return
}
}
func Query() {
// 查询
//book, err := query.Book.WithContext(context.Background()).First()
// 也可以使用全局Q对象查询
book, err := query.Q.Book.WithContext(context.Background()).First()
if err != nil {
fmt.Printf("query book fail, err:%v\n", err)
return
}
fmt.Printf("book:%v\n", book)
}
func Update() {
// 更新
ret, err := query.Book.WithContext(context.Background()).
Where(query.Book.ID.Eq(1)).
Update(query.Book.Price, 200)
if err != nil {
fmt.Printf("update book fail, err:%v\n", err)
return
}
fmt.Printf("RowsAffected:%v\n", ret.RowsAffected)
}
func Del() {
// 删除
ret, err := query.Book.WithContext(context.Background()).Where(query.Book.ID.Eq(1)).Delete()
if err != nil {
fmt.Printf("delete book fail, err:%v\n", err)
return
}
fmt.Printf("RowsAffected:%v\n", ret.RowsAffected)
}
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# 03.自定义SQL查询
# 0、语法说明
- Gen框架使用模板注释的方法支持自定义SQL查询,我们只需要按对应规则将SQL语句注释到interface的方法上即可
- Gen将对其进行解析,并为应用的结构生成查询API,通常建议将自定义查询方法添加到
model
模块下。
注释语法
Gen 为动态条件 SQL 支持提供了一些约定语法,分为三个方面:
返回结果
模板占位符
模板表达式
返回结果
占位符 | 含义 |
---|---|
gen.T | 用于返回数据的结构体,会根据生成结构体或者数据库表结构自动生成 |
gen.M | 表示map[string]interface{} ,用于返回数据 |
gen.RowsAffected | 用于执行SQL进行更新或删除时候,用于返回影响行数 |
error | 返回错误(如果有) |
# 1、gen_demo/dal/model/querier.go
// dal/model/querier.go
package model
import "gorm.io/gen"
// 通过添加注释生成自定义方法
type Querier interface {
// SELECT * FROM @@table WHERE id=@id
GetByID(id int) (gen.T, error) // 返回结构体和error
// GetByIDReturnMap 根据ID查询返回map
//
// SELECT * FROM @@table WHERE id=@id
GetByIDReturnMap(id int) (gen.M, error) // 返回 map 和 error
// SELECT * FROM @@table WHERE author=@author
GetBooksByAuthor(author string) ([]*gen.T, error) // 返回数据切片和 error
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 2、gen_demo/cmd/gen/generate.go
// 通过ApplyInterface添加为book表添加自定义方法
g.ApplyInterface(func(model.Querier) {}, g.GenerateModel("book"))
1
2
2
- 生成代码
cd cmd/gen
go run generate.go
1
2
2
# 3、main.go
func GetDefine() {
// 使用自定义的GetBooksByAuthor方法
rets, err := query.Book.WithContext(context.Background()).GetBooksByAuthor("七米")
if err != nil {
fmt.Printf("GetBooksByAuthor fail, err:%v\n", err)
return
}
for i, b := range rets {
fmt.Printf("%d:%v\n", i, b)
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 04.模板占位符
名称 | 描述 |
---|---|
@@table | 转义和引用表名 |
@@<name> | 从参数中转义并引用表/列名 |
@<name> | 参数中的SQL查询参数 |
# 1、gen_demo/dal/model/querier.go
// Filter 自定义Filter接口
type Filter interface {
// SELECT * FROM @@table WHERE @@column=@value
FilterWithColumn(column string, value string) (gen.T, error)
}
1
2
3
4
5
2
3
4
5
# 2、gen_demo/cmd/gen/generate.go
// 为`Book`添加 `Filter`接口
g.ApplyInterface(func(model.Filter) {}, g.GenerateModel("book"))
1
2
2
# 3、main.go
func GetFilter() {
// 使用自定义的GetBooksByAuthor方法
rets, err := query.Book.WithContext(context.Background()).FilterWithColumn("author", "七米")
if err != nil {
fmt.Printf("GetBooksByAuthor fail, err:%v\n", err)
return
}
fmt.Println(rets)
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 05.模板表达式
Gen 为动态条件 SQL 提供了强大的表达式支持,目前支持以下表达式:
if/else
where
set
for
# 1、gen_demo/dal/model/querier.go
// Searcher 自定义接口
type Searcher interface {
// Search 根据指定条件查询书籍
//
// SELECT * FROM book
// WHERE publish_date is not null
// {{if book != nil}}
// {{if book.ID > 0}}
// AND id = @book.ID
// {{else if book.Author != ""}}
// AND author=@book.Author
// {{end}}
// {{end}}
Search(book *gen.T) ([]*gen.T, error)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 2、gen_demo/cmd/gen/generate.go
// 通过ApplyInterface添加为book表添加Searcher接口
g.ApplyInterface(func(model.Searcher) {}, g.GenerateModel("book"))
1
2
2
# 3、main.go
func GetSearch() {
b := &model.Book{Author: "张三"}
rets, err := query.Book.WithContext(context.Background()).Search(b)
if err != nil {
fmt.Printf("Search fail, err:%v\n", err)
return
}
for i, b := range rets {
fmt.Printf("%d:%v\n", i, b)
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
上次更新: 2024/3/13 15:35:10