零基础上手更安全更友好GORM原作者操刀的GORM GEN

GORM/GEN,持续更新欢迎吐槽Star!!!

基于 GORM, 更安全更友好的ORM工具。

Overview

  • 自动生成CRUD和DIY方法
  • 自动根据表结构生成model
  • 完全兼容GORM
  • 更安全、更友好
  • 多种生成代码模式

安装

安装GEN前,需要安装好GO并配置你的工作环境。

1.安装完Go(version 1.14+)之后,通过下面的命令安装gen。

go get -u gorm.io/gen

2.导入到你的工程:

import "gorm.io/gen"

快速开始

注⚠️: 这里所有的教程都是在 WithContext 模式下写的. 如果你用的是WithoutContext 模式,则可以删除所有的 WithContext(ctx) ,这样代码看起来会更简洁.

# assume the following code in generate.go file
$ cat generate.go
package main

import "gorm.io/gen"

// generate code
func main() {
   
    // specify the output directory (default: "./query")
    // ### if you want to query without context constrain, set mode gen.WithoutContext ###
    g := gen.NewGenerator(gen.Config{
   
        OutPath: "../dal/query",
        /* Mode: gen.WithoutContext|gen.WithDefaultQuery*/
        //if you want the nullable field generation property to be pointer type, set FieldNullable true
        /* FieldNullable: true,*/
        //if you want to generate index tags from database, set FieldWithIndexTag true
        /* FieldWithIndexTag: true,*/
        //if you want to generate type tags from database, set FieldWithTypeTag true
        /* FieldWithTypeTag: true,*/
        //if you need unit tests for query code, set WithUnitTest true
        /* WithUnitTest: true, */
    })
  
    // reuse the database connection in Project or create a connection here
    // if you want to use GenerateModel/GenerateModelAs, UseDB is necessray or it will panic
    // db, _ := gorm.Open(mysql.Open("root:@(127.0.0.1:3306)/demo?charset=utf8mb4&parseTime=True&loc=Local"))
    g.UseDB(db)
  
    // apply basic crud api on structs or table models which is specified by table name with function
    // GenerateModel/GenerateModelAs. And generator will generate table models' code when calling Excute.
    g.ApplyBasic(model.User{
   }, g.GenerateModel("company"), g.GenerateModelAs("people", "Person", gen.FieldIgnore("address")))
    
    // apply diy interfaces on structs or table models
    g.ApplyInterface(func(method model.Method) {
   }, model.User{
   }, g.GenerateModel("company"))

    // execute the action of code generation
    g.Execute()
}

生成Model:

  • gen.WithoutContextWithContext 模式生成
  • gen.WithDefaultQuery 生成默认全局查询变量

项目路径

最佳实践项目模板:

demo
├── cmd
│   └── generate
│       └── generate.go # execute it will generate codes
├── dal
│   ├── dal.go # create connections with database server here
│   ├── model
│   │   ├── method.go # DIY method interfaces
│   │   └── model.go  # store struct which corresponding to the database table
│   └── query  # generated code's directory
|       ├── user.gen.go # generated code for user
│       └── gen.go # generated code
├── biz
│   └── query.go # call function in dal/gorm_generated.go and query databases
├── config
│   └── config.go # DSN for database server
├── generate.sh # a shell to execute cmd/generate
├── go.mod
├── go.sum
└── main.go

API 示例

生成

生成Model
// generate a model struct map to table `people` in database
g.GenerateModel("people")

// generate a struct and specify struct's name
g.GenerateModelAs("people", "People")

// add option to ignore field
g.GenerateModel("people", gen.FieldIgnore("address"), gen.FieldType("id", "int64"))

// generate all tables, ex: g.ApplyBasic(g.GenerateAllTable()...)
g.GenerateAllTable()

字段生成 Options

FieldNew           // create new field
FieldIgnore        // ignore field
FieldIgnoreReg     // ignore field (match with regexp)
FieldRename        // rename field in struct
FieldType          // specify field type
FieldTypeReg       // specify field type (match with regexp)
FieldTag           // specify gorm and json tag
FieldJSONTag       // specify json tag
FieldGORMTag       // specify gorm tag
FieldNewTag        // append new tag
FieldNewTagWithNS  // specify new tag with name strategy
FieldTrimPrefix    // trim column prefix
FieldTrimSuffix    // trim column suffix
FieldAddPrefix     // add prefix to struct member's name
FieldAddSuffix     // add suffix to struct member's name
FieldRelate        // specify relationship with other tables
FieldRelateModel   // specify relationship with exist models
类型映射

自定义数据库字段类型和go类型的映射关系.

dataMap := map[string]func(detailType string) (dataType string){
   
  "int": func(detailType string) (dataType string) {
    return "int64" },
  // bool mapping
  "tinyint": func(detailType string) (dataType string) {
   
    if strings.HasPrefix(detailType, "tinyint(1)") {
   
      return "bool"
    }
    return "int8"
  },
}

g.WithDataTypeMap(dataMap)

字段表达式

创建字段

实际上你需要手动创建字段,因为都会在生成代码自动创建。

Field Type Detail Type Create Function Supported Query Method
generic field NewField IsNull/IsNotNull/Count/Eq/Neq/Gt/Gte/Lt/Lte/Like
int int/int8/…/int64 NewInt/NewInt8/…/NewInt64 Eq/Neq/Gt/Gte/Lt/Lte/In/NotIn/Between/NotBetween/Like/NotLike/Add/Sub/Mul/Div/Mod/FloorDiv/RightShift/LeftShift/BitXor/BitAnd/BitOr/BitFlip
uint uint/uint8/…/uint64 NewUint/NewUint8/…/NewUint64 same with int
float float32/float64 NewFloat32/NewFloat64 Eq/Neq/Gt/Gte/Lt/Lte/In/NotIn/Between/NotBetween/Like/NotLike/Add/Sub/Mul/Div/FloorDiv
string string/[]byte NewString/NewBytes Eq/Neq/Gt/Gte/Lt/Lte/Between/NotBetween/In(val/NotIn(val/Like/NotLike/Regexp/NotRegxp/FindInSet/FindInSetWith
bool bool NewBool Not/Is/And/Or/Xor/BitXor/BitAnd/BitOr
time time.Time NewTime Eq/Neq/Gt/Gte/Lt/Lte/Between/NotBetween/In/NotIn/Add/Sub

创建字段示例:

import "gorm.io/gen/field"

// create a new generic field map to `generic_a`
a := field.NewField("table_name", "generic_a")

// create a field map to `id`
i := field.NewInt("user", "id")

// create a field map to `address`
s := field.NewString("user", "address")

// create a field map to `create_time`
t := field.NewTime("user", "create_time")

CRUD 接口

生成基础model userDB.

// generated code
// generated code
// generated code
package query

import "gorm.io/gen"

// struct map to table `users` 
type user struct {
   
    gen.DO
    ID       field.Uint
    Name     field.String
    Age      field.Int
    Address  field.Field
    Birthday field.Time
}

// struct collection
type DB struct {
   
    db       *gorm.DB
    User     *user
}
创建
创建记录
// u refer to query.user
user := model.User{
   Name: "Modi", Age: 18, Birthday: time.Now()}

u := query.Use(db).User
err := u.WithContext(ctx).Create(&user) // pass pointer of data to Create

err // returns error
选择字段创建

自定义哪些字段需要插入。

u := query.Use(db).User
u.WithContext(ctx).Select(u.Name, u.Age).Create(&user)
// INSERT INTO `users` (`name`,`age`) VALUES ("modi", 18)

自定义创建时需要忽略的字段。

u := query.Use(db).User
u.WithContext(ctx).Omit(u.Name, u.Age).Create(&user)
// INSERT INTO `users` (`Address`, `Birthday`) VALUES ("2021-08-17 20:54:12.000", 18)
批量创建

Create 方法支持批量创建,参数只要是对应model的slice就可以. GORM会通过一条语句高效创建并返回所有的主键赋值给slice的Model.

var users = []model.User{
   {
   Name: "modi"}, {
   Name: "zhangqiang"}, {
   Name: "songyuan"}}
query.Use(db).User.WithContext(ctx).Create(&users)

for _, user := range users {
   
    user.ID // 1,2,3
}

CreateInBatches可以指定批量创建的大小, e.g:

var users = []User{
   {
   Name: "modi_1"}, ...., {
   Name: "modi_10000"}}

// batch size 100
query.Use(db).User.WithContext(ctx).CreateInBatches(users, 100)

也可以通过全局配置方式,在初始化gorm时设置 CreateBatchSize in gorm.Config / gorm.Session

db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
   
    CreateBatchSize: 1000,
})
// OR
db = db.Session(&gorm.Session{
   CreateBatchSize: 1000})

u := query.NewUser(db)

var users = []User{
   {
   Name: "modi_1"}, ...., {
   Name: "modi_5000"}}

u.WithContext(ctx).Create(&users)
// INSERT INTO users xxx (5 batches)
查询
单个数据查询

自动生成 First, Take, Last 三个查询单条数据的方法。 执行的sql后面会自动添加 LIMIT 1 ,如果没有查到数据会返回错误: ErrRecordNotFound

u := query.Use(db).User

// Get the first record ordered by primary key
user, err := u.WithContext(ctx).First()
// SELECT * FROM users ORDER BY id LIMIT 1;

// Get one record, no specified order
user, err := u.WithContext(ctx).Take()
// SELECT * FROM users LIMIT 1;

// Get last record, ordered by primary key desc
user, err := u.WithContext(ctx).Last()
// SELECT * FROM users ORDER BY id DESC LIMIT 1;

// check error ErrRecordNotFound
errors.Is(err, gorm.ErrRecordNotFound)
根据主键查询数据
u := query.Use(db).User

user, err := u.WithContext(ctx).Where(u.ID.Eq(10)).First()
// SELECT * FROM users WHERE id = 10;

users, err := u.WithContext(ctx).Where(u.ID.In(1,2,3)).Find()
// SELECT * FROM users WHERE id IN (1,2,3);

如果是string类型的主键,比如UUID等:

user, err := u.WithContext(ctx).Where(u.ID.Eq("1b74413f-f3b8-409f-ac47-e8c062e3472a")).First()
// SELECT * FROM users WHERE id = "1b74413f-f3b8-409f-ac47-e8c062e3472a";
查询所有数据
u := query.Use(db).User

// Get all records
users, err := u.WithContext(ctx).Find()
// SELECT * FROM users;
条件
基础查询
u := query.Use(db).User

// Get first matched record
user, err := u.WithContext(ctx).Where(u.Name.Eq("modi")).First()
// SELECT * FROM users WHERE name = 'modi' ORDER BY id LIMIT 1;

// Get all matched records
users, err := u.WithContext(ctx).Where(u.Name.Neq("modi")).Find()
// SELECT * FROM users WHERE name <> 'modi';

// IN
users, err := u.WithContext(ctx).Where(u.Name.In("modi", "zhangqiang")).Find()
// SELECT * FROM users WHERE name IN ('modi','zhangqiang');

// LIKE
users, err := u.WithContext(ctx).Where(u.Name.Like("%modi%")).Find()
// SELECT * FROM users WHERE name LIKE '%modi%';

// AND
users, err := u.WithContext(ctx).Where(u.Name.Eq("modi"), u.Age.Gte(17)).Find()
// SELECT * FROM users WHERE name = 'modi' AND age >= 17;

// Time
users, err := u.WithContext(ctx).Where(u.Birthday.Gt(birthTime).Find()
// SELECT * FROM users WHERE birthday > '2000-01-01 00:00:00';

// BETWEEN
users, err := u.WithContext(ctx).Where(u.Birthday.Between(lastWeek, today)).Find()
// SELECT * FROM users WHERE birthday BETWEEN '2000-01-01 00:00:00' AND '2000-01-08 00:00:00';
Not
u := query.Use(db).User

user, err := u.WithContext(ctx).Not(u.Name.Eq("modi")).First()
// SELECT * FROM users WHERE NOT name = "modi" ORDER BY id LIMIT 1;

// Not In
users, err := u.WithContext(ctx).Not(u.Name.In("modi", "zhangqiang")).Find()
// SELECT * FROM users WHERE name NOT IN ("modi", "zhangqiang");

// Not In slice of primary keys
user, err := u.WithContext(ctx).Not(u.ID.In(1,2,3)).First()
// SELECT * FROM users WHERE id NOT IN (1,2,3) ORDER BY id LIMIT 1;
Or
u := query.Use(db).User

users, err := u.WithContext(ctx).Where(u.Role.Eq("admin")).Or(u.Role.Eq("super_admin")).Find()
// SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';
Group

组合where或or 构建复杂查询

p := query.Use(db).Pizza

pizzas, err := p.WithContext(ctx).Where(
    p.WithContext(ctx).Where(p.Pizza.Eq("pepperoni")).
        Where(p.Where
  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值