介绍一个 Golang 生成模型的工具

市面上有很多的工具可以通过读取mysql的表,生成 golang 结构体作为 gorm 模型使用了

但是为什么我用了就放弃了?因为只是生成模型还不够!

正常模型定义好之后,通过 gorm 就能愉快的简单的进行 CURD 了,不过在简单和复杂的sql操作中,我们可以更方便、更直观的操作

而这个 gormstruct 工具可以根据表名生成表结构体和数据操作方法

一、 提供的功能

(一)关于模型

  1. **生成模型 :**生成gorm 模型,包含每个字段的注释,注释统一在右边//对齐,方便全局观察字段的定义情况。
  2. **生成表的所有字段映射:*使用字段自定义查询时,统一使用映射的字段,在字段的维护上更方便;同时默认查询所有字段,不使用,不使用反射查询所有字段。
  3. **为所有字段生成SetXxx()GetXxx()方法:**用户设置/获取模型下指定字段的值

(二)关于dao层

自动判断是否存在软删除字段,存在则默认过滤非软删除记录

  1. **生成操作表的基本方法:**base_dao.go
  2. **生成Save()方法:**存在则更新,否则插入
  3. **生成Create()方法:**创建数据:允许单条/批量创建,批量创建时传入切片
  4. **为所有字段生成 WithXxx方法:**将单个字段的值作为查询条件
  5. **为所有字段生成 WithXxxs方法(多一个s):**将单个字段的列表值作为查询条件
  6. **生成GetByOption()方法:**函数选项模式获取单条记录
  7. **生成GetListByOption方法:**函数选项模式获取多条记录:支持分页
  8. **生成GetCountByOption()方法:**函数选项模式获取多条记录:支持统计记录总数
  9. **生成GetCustomeResultByOption()方法:**函数选项模式获取多条记录到自定义结构体(result:务必使用指针变量):支持包含自定义聚合字段(自定义的聚合字段务必添加 gorm:“column:字段的别名;” 标签)
  10. **生成UpdateByOption():**更新数据
  11. **生成``GetFromXxx()`方法:**简单直接通过单个字段值获取数据(自动判断该字段是否设置唯一索引,否则自动获取单条记录,反之则是多条记录)
  12. **生成GetsFromXxx()方法:**简单直接通过单个字段的列表值获取多条记录
  13. **生成FetchByXxx()方法:**通过索引(唯一索引(主键、唯一索引、唯一复合索引)、非唯一索引(普通索引))作为查询条件获取数据(自动判断索引类型确定获取单条记录还是多条记录)

所有的方法:在项目中都包含相应的测试用例test/xxx_test.go

如果觉得哪些功能需要改进的欢迎留言,最近还发现一个不错的学习网站推荐给大家 itgogogo.cn , 内容丰富,收集了很多学习资料和面试指南。

二、使用步骤

  1. 克隆项目到本地(https://github.com/leeprince/gormstruct)
  2. 重命名./config/config.bak.yaml./config/config.yaml
  3. 修改dbinfo为自己的数据库链接配置
# 数据库设置
dbinfo:
  host: 127.0.0.1
  port: 3306
  username: root
  password: root
  database: ticket # 该参数可通过命令行设置,命令行设置会覆盖该值。如果未设置则必须在命令中指定
  type: 0 # 数据库类型:0:mysql
  1. 运行指令go run main.go -t={数据库下的表名}或者 ./gormstruct -t={数据库下的表名}
    会在./out/model下生成3个文件
  • 模型:表名xxx.go
  • dao层:表名_dao.go
  • 基础dao层:base.go(只有在第一次该工具时生成)

三、示例

(一)配置项


# 数据库设置
dbinfo:
  host: 127.0.0.1
  port: 3306
  username: root
  password: root
  database: tmp # 该参数可通过命令行设置,命令行设置会覆盖该值。如果未设置则必须在命令中指定
  type: 0 # 数据库类型:0:mysql
  
# --- 建议保留默认 ---------
# 是否控制台输出数据库表结构文档
gendoc: true
# 自定义数据库字段的数据类型映射 golang 的数据类型
self_type_define:
  int(11):             int64
  int(11) unsigned:    uint64
  smallint:            int16
  smallint unsigned:   uint16
  int:                 int64
  int unsigned:        int64
  bigint:              int64
  bigint unsigned:     uint64
  mediumint:           int32
  mediumint unsigned:  uint32
  varchar:             string
  char:                string
  date:                datatypes.Date
  datetime:            time.Time
  bit(1):              "[]uint8"
  tinyint:             int8
  tinyint unsigned:    uint8
  tinyint(1):          int8
  tinyint(1) unsigned: uint8
  tinyint(2):          int8
  tinyint(2) unsigned: uint8
  tinyint(3):          int8
  tinyint(3) unsigned: uint8
  json:                datatypes.JSON
  text:                string
  timestamp:           time.Time
  double:              float64
  double unsigned:     float64
  mediumtext:          string
  longtext:            string
  float:               float32
  float unsigned:      float32
  tinytext:            string
  enum:                string
  time:                time.Time
  tinyblob:            "[]byte"
  blob:                "[]byte"
  mediumblob:          "[]byte"
  longblob:            "[]byte"
  integer:             int64

# 默认包名
packagename: model

# 输出的文件路径
ouput_dir: ./out/model/

# 是否自动根据存在 id+created_at+updated_at+deleted_at 字段时,统一使用 gorm 的结构体 `gorm.Model` 覆盖
# true: 因为 gorm.model 默认这三个时间字段为time.Time数据类型,所以需要表设置的数据类型为时间类型:date、datetime、timestamp, 并且允许为NULL。否则字段值为非NULL,并且查询记录存在时会报:unsupported Scan, storing driver.Value type []uint8 into type *time.Time。其中自动设置 `deleted_at` IS NULL,除非添加`db.Unscoped()`方法。由于该包已经支持自定义所以,不支持设置为true
# false: 强制为false
is_gorm_model_tag: false

# 设置 "is_gorm_model_tag=true"时主键ID的数据类型
primary_id_type: int64

# 字段允许为Null时是否设置为指针类型
#   设置指针类型的条件:配置允许设置为指针类型&字段允许为null&字段的数据类型为uint|int|float|string
#   设置指针的好处是:通过 gorm 的模型结构体执行更新操作时会更新字段为设置的零值
is_null_to_point: true

# 自定义的行记录删除字段列表
delete_flag_field_list:
  - is_delete
  - is_deleted
  - deleted_at

# --- 建议保留默认-end ---------

(二)生成文件部分示例

1. 表模型

user.go

package model

// 用户表
type Users struct {
	ID        int64   `gorm:"column:id;primaryKey;type:int(11);autoIncrement" json:"id"`             // 主键
	Name      *string `gorm:"column:name;type:varchar(255);is null;" json:"name"`                    // 名称
	Age       int64   `gorm:"column:age;type:int(11);not null;DEFAULT '18'" json:"age"`              // 年龄
	CardNo    string  `gorm:"column:card_no;type:varchar(18);not null;DEFAULT ''" json:"card_no"`    // 身份证
	HeadImg   string  `gorm:"column:head_img;type:varchar(255);not null;DEFAULT ''" json:"head_img"` // 头像
	CreatedAt int64   `gorm:"column:created_at;type:int(11);not null;" json:"created_at"`            // 创建时间
	UpdatedAt int64   `gorm:"column:updated_at;type:int(11);not null;" json:"updated_at"`            // 更新时间
	DeletedAt int64   `gorm:"column:deleted_at;type:int(11);not null;DEFAULT '0'" json:"deleted_at"` // 删除时间
}

// 获取结构体对应的表名方法
func (m *Users) TableName() string {
	return "users"
}

// 实例化结构体对象
func NewUsers() *Users {
	return &Users{}
}

// 获取主键的对应字段
func (m *Users) PrimaryKey() string {
	return UsersColumns.ID
}

// 获取主键值
func (m *Users) PrimaryKeyValue() int64 {
	return m.ID
}

// 表字段的映射
var UsersColumns = struct {
	ID        string
	Name      string
	Age       string
	CardNo    string
	HeadImg   string
	CreatedAt string
	UpdatedAt string
	DeletedAt string
}{
	ID:        "id",
	Name:      "name",
	Age:       "age",
	CardNo:    "card_no",
	HeadImg:   "head_img",
	CreatedAt: "created_at",
	UpdatedAt: "updated_at",
	DeletedAt: "deleted_at",
}

// 包含所有表字段的切片
var UsersAllColumns = []string{
	UsersColumns.ID,        // 主键
	UsersColumns.Name,      // 名称
	UsersColumns.Age,       // 年龄
	UsersColumns.CardNo,    // 身份证
	UsersColumns.HeadImg,   // 头像
	UsersColumns.CreatedAt, // 创建时间
	UsersColumns.UpdatedAt, // 更新时间
	UsersColumns.DeletedAt, // 删除时间

}

// 设置值:主键
func (m *Users) SetID(v int64) {
	m.ID = v
}

// 设置值:名称
func (m *Users) SetName(v *string) {
	m.Name = v
}

...
2. 基础dao层

base_dao.go(只有在第一次该工具时生成)

package model

import (
	"context"
	"gorm.io/gorm"
	"time"
)

const (
	// 分页器时,默认允许最大的记录数
	MaxLimit = 1000
)

// 初始化 gorm 实例的其他字段
type _BaseDAO struct {
	*gorm.DB
	db               *gorm.DB
	model            interface{}
	ctx              context.Context
	cancel           context.CancelFunc
	timeout          time.Duration
	columns          []string
	isDefaultColumns bool
}

// 设置超时
func (obj *_BaseDAO) SetTimeOut(timeout time.Duration) {
	obj.ctx, obj.cancel = context.WithTimeout(context.Background(), timeout)
	obj.timeout = timeout
}

// 设置上下文
func (obj *_BaseDAO) SetCtx(c context.Context) {
	if c != nil {
		obj.ctx = c
	}
}

// 获取上下文
func (obj *_BaseDAO) GetCtx() context.Context {
	return obj.ctx
}

// 取消上下文
func (obj *_BaseDAO) Cancel(c context.Context) {
	obj.cancel()
}

// 获取 DB 实例
func (obj *_BaseDAO) GetDBModel() *gorm.DB {
	return obj.DB.Model(&obj.model)
}

// 更新 DB 实例
func (obj *_BaseDAO) UpdateDB(db *gorm.DB) {
	obj.DB = db
}

// 重置 gorm 会话
func (obj *_BaseDAO) NewDB() *gorm.DB {
	return obj.GetDBModel().Session(&gorm.Session{NewDB: true, Context: obj.ctx})
}

// 开启事务:开启事务之后,必须使用开启事务返回的*gorm.DB, 而不是开启事务时使用*gorm.DB
func (obj *_BaseDAO) BeginTx() {
	obj.UpdateDB(obj.GetDBModel().Begin())
}

// 事务回滚
func (obj *_BaseDAO) RollbackTx() {
	obj.UpdateDB(obj.GetDBModel().Rollback())
	obj.UpdateDB(obj.db)
}

// 事务提交
func (obj *_BaseDAO) CommitTx() {
	obj.UpdateDB(obj.GetDBModel().Commit())
	obj.UpdateDB(obj.db)
}

// 设置上下文获取 *grom.DB
func (obj *_BaseDAO) withContext() (db *gorm.DB) {
	return obj.GetDBModel().WithContext(obj.ctx)
}

// 设置 sql 语句是否默认选择表的所有字段:没有通过WithSelect指定字段时,是否默认选择表的所有字段。更新/统计(count)语句时设置为false。
func (obj *_BaseDAO) setIsDefaultColumns(b bool) {
	obj.isDefaultColumns = b
}

// 查询指定字段
func (obj *_BaseDAO) WithSelect(query interface{}, args ...interface{}) Option {
	return selectOptionFunc(func(o *options) {
		o.selectField = queryArg{
			query: query,
			arg:   args,
		}
	})
}

// 自定义查询条件
func (obj *_BaseDAO) WithWhere(query interface{}, args ...interface{}) Option {
	return queryArgOptionFunc(func(o *options) {
		o.queryArg = queryArg{
			query: query,
			arg:   args,
		}
	})
}

// Or 查询:将所有 Withxxx 的 options.queryMap 作为 Or 的查询条件
func (obj *_BaseDAO) WithOrOption(opts ...Option) Option {
	optionOr := initOption(opts...)

	return queryOrOptionFunc(func(o *options) {
		if len(optionOr.queryMap) > 0 {
			o.queryMapOr = make(map[string]interface{}, len(optionOr.queryMap))
			for key, value := range optionOr.queryMap {
				o.queryMapOr[key] = value
			}
		}
	})
}

// 设置 offset、limit 作为 option 条件支持分页
func (obj *_BaseDAO) WithPage(offset int, limit int) Option {
	return pageOptionFunc(func(o *options) {
		o.page.offset = offset
		o.page.limit = limit
	})
}

// 设置 offset、limit 作为 option 条件支持分页
func (obj *_BaseDAO) WithOrderBy(orderBy string) Option {
	return orderByOptionFunc(func(o *options) {
		o.orderBy = orderBy
	})
}

// 分组
func (obj *_BaseDAO) WithGroupBy(groupBy string) Option {
	return groupByOptionFunc(func(o *options) {
		o.groupBy = groupBy
	})
}

// 分组后筛选
func (obj *_BaseDAO) WithHaving(query interface{}, args ...interface{}) Option {
	return havingByOptionFunc(func(o *options) {
		o.having = queryArg{
			query: query,
			arg:   args,
		}
	})
}

// 执行 sql 前的准备
func (obj *_BaseDAO) prepare(opts ...Option) (tx *gorm.DB) {
	options := initOption(opts...)

	tx = obj.withContext().
		Scopes(obj.selectField(&options)).
		Scopes(obj.queryArg(&options)).
		Where(options.queryMap).
		Or(options.queryMapOr).
		Scopes(obj.paginate(&options)).
		Scopes(obj.orderBy(&options)).
		Scopes(obj.groupBy(&options)).
		Scopes(obj.having(&options))
	return
}

// 选择字段
func (obj *_BaseDAO) selectField(opt *options) func(*gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		if opt.selectField.query != nil && opt.selectField.query != "" {
			if opt.selectField.arg != nil && len(opt.selectField.arg) > 0 {
				return db.Select(opt.selectField.query, opt.selectField.arg...)
			}
			return db.Select(opt.selectField.query)
		} else if obj.isDefaultColumns {
			return db.Select(obj.columns)
		}
		return db
	}
}

// 自定义查询条件
func (obj *_BaseDAO) queryArg(opt *options) func(*gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		if opt.queryArg.query != nil && opt.queryArg.query != "" {
			if opt.queryArg.arg != nil && len(opt.queryArg.arg) > 0 {
				return db.Where(opt.queryArg.query, opt.queryArg.arg...)
			}
			return db.Where(opt.queryArg.query)
		}
		return db
	}
}

// 排序
func (obj *_BaseDAO) orderBy(opt *options) func(*gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		if opt.orderBy != "" {
			return db.Order(opt.orderBy)
		}
		return db
	}
}

// 分组
func (obj *_BaseDAO) groupBy(opt *options) func(*gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		if opt.groupBy != "" {
			return db.Group(opt.groupBy)
		}
		return db
	}
}

// 分组后筛选
func (obj *_BaseDAO) having(opt *options) func(*gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		if opt.having.query != nil && opt.having.query != "" {
			if opt.having.arg != nil && len(opt.having.arg) > 0 {
				return db.Having(opt.having.query, opt.having.arg)
			}
			return db.Having(opt.having.query)
		}
		return db
	}
}

// 分页器
func (obj *_BaseDAO) paginate(opt *options) func(*gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		if opt.page.limit <= 0 {
			return db
		}
		if opt.page.limit > MaxLimit {
			opt.page.limit = MaxLimit
		}
		return db.Offset(opt.page.offset).Limit(opt.page.limit)
	}
}

// 函数选项模式的参数字段
type options struct {
	// 指定字段:查询指定字段或者更新指定字段
	selectField queryArg
	// 自定义查询条件
	queryArg queryArg
	// 查询条件AND
	queryMap map[string]interface{}
	// 查询条件OR
	queryMapOr map[string]interface{}
	// 分页
	page paging
	// 排序
	orderBy string
	// 分组
	groupBy string
	// 分组后的条件过滤条件
	having queryArg
}

// query-arg数据结构
type queryArg struct {
	query interface{}
	arg   []interface{}
}

// 分页数据结构
type paging struct {
	offset int
	limit  int
}

// 函数选项模式接口
type Option interface {
	apply(*options)
}

// options.selectOptionFunc 实现 Option 接口
type selectOptionFunc func(*options)

func (f selectOptionFunc) apply(o *options) {
	f(o)
}

// options.queryArg 实现 Option 接口
type queryArgOptionFunc func(*options)

func (f queryArgOptionFunc) apply(o *options) {
	f(o)
}

// options.queryMap 实现 Option 接口
type queryOptionFunc func(*options)

func (f queryOptionFunc) apply(o *options) {
	f(o)
}

// options.queryMap 实现 Option 接口
type queryOrOptionFunc func(*options)

func (f queryOrOptionFunc) apply(o *options) {
	f(o)
}

// options.page 实现 Option 接口
type pageOptionFunc func(*options)

func (f pageOptionFunc) apply(o *options) {
	f(o)
}

// options.update 实现 Option 接口
type orderByOptionFunc func(*options)

func (f orderByOptionFunc) apply(o *options) {
	f(o)
}

// options.update 实现 Option 接口
type groupByOptionFunc func(*options)

func (f groupByOptionFunc) apply(o *options) {
	f(o)
}

// options.update 实现 Option 接口
type havingByOptionFunc func(*options)

func (f havingByOptionFunc) apply(o *options) {
	f(o)
}

// 初始化 options
func initOption(opts ...Option) options {
	opt := options{
		selectField: queryArg{
			query: nil,
			arg:   nil,
		},
		queryArg: queryArg{
			query: nil,
			arg:   nil,
		},
		queryMap:   make(map[string]interface{}, len(opts)),
		queryMapOr: make(map[string]interface{}, len(opts)),
		page: paging{
			offset: 0,
			limit:  0,
		},
		orderBy: "",
		groupBy: "",
	}
	for _, o := range opts {
		o.apply(&opt)
	}
	return opt
}

3. 表相应的DAO层

user_dao.go

package model

import (
	"context"
	"fmt"
	"gorm.io/gorm"
)

type UsersDAO struct {
	*_BaseDAO
}

// UsersDAO 初始化
func NewUsersDAO(ctx context.Context, db *gorm.DB) *UsersDAO {
	if db == nil {
		panic(fmt.Errorf("UsersDAO need init by db"))
	}
	ctx, cancel := context.WithCancel(ctx)
	return &UsersDAO{
		_BaseDAO: &_BaseDAO{
			DB:               db.Model(&Users{}),
			db:               db,
			model:            Users{},
			ctx:              ctx,
			cancel:           cancel,
			timeout:          -1,
			columns:          UsersAllColumns,
			isDefaultColumns: true,
		},
	}
}

// GetTableName 获取表名称
func (obj *UsersDAO) GetTableName() string {
	users := &Users{}
	return users.TableName()
}

// Save 存在则更新,否则插入
func (obj *UsersDAO) Save(users *Users) (rowsAffected int64, err error) {
	if users.PrimaryKeyValue() > 0 {
		return obj.UpdateByOption(users, obj.WithID(users.ID))
	}
	return obj.Create(users)
}

// Create 创建数据:允许单条/批量创建,批量创建时传入切片
func (obj *UsersDAO) Create(users interface{}) (rowsAffected int64, err error) {
	tx := obj.withContext().Create(users)
	return tx.RowsAffected, tx.Error
}

// --- 表中的字段作为 option 条件 ---

// WithID 设置 id(主键) 字段作为 option 条件
func (obj *UsersDAO) WithID(id int64) Option {
	return queryOptionFunc(func(o *options) { o.queryMap[UsersColumns.ID] = id })
}

// WithIDs 设置 id(主键) 字段的切片作为 option 条件
func (obj *UsersDAO) WithIDs(ids []int64) Option {
	return queryOptionFunc(func(o *options) { o.queryMap[UsersColumns.ID] = ids })
}
...

// WithDeletedAt 设置 deleted_at(删除时间) 字段作为 option 条件
func (obj *UsersDAO) WithDeletedAt(deletedAt int64) Option {
	return queryOptionFunc(func(o *options) { o.queryMap[UsersColumns.DeletedAt] = deletedAt })
}

// WithDeletedAts 设置 deleted_at(删除时间) 字段的切片作为 option 条件
func (obj *UsersDAO) WithDeletedAts(deletedAts []int64) Option {
	return queryOptionFunc(func(o *options) { o.queryMap[UsersColumns.DeletedAt] = deletedAts })
}

// GetByOption 函数选项模式获取单条记录
func (obj *UsersDAO) GetByOption(opts ...Option) (result *Users, err error) {
	opts = append(opts, obj.WithDeletedAt(0))
	err = obj.prepare(opts...).Find(&result).Error
	return
}

// GetListByOption 函数选项模式获取多条记录:支持分页
func (obj *UsersDAO) GetListByOption(opts ...Option) (results []*Users, err error) {
	opts = append(opts, obj.WithDeletedAt(0))
	err = obj.prepare(opts...).Find(&results).Error
	return
}

// GetCountByOption 函数选项模式获取多条记录:支持统计记录总数
func (obj *UsersDAO) GetCountByOption(opts ...Option) (count int64) {
	obj.setIsDefaultColumns(false)
	opts = append(opts, obj.WithDeletedAt(0))
	obj.prepare(opts...).Count(&count)
	return
}

// GetCustomeResultByOption 函数选项模式获取多条记录到自定义结构体(result:务必使用指针变量):支持包含自定义聚合字段(自定义的聚合字段务必添加 gorm:"column:字段的别名;" 标签)
func (obj *UsersDAO) GetCustomeResultByOption(result interface{}, opts ...Option) (err error) {
	err = obj.prepare(opts...).Find(result).Error
	return
}

// UpdateByOption 更新数据
//
//		参数说明:
//	     users: 要更新的数据
//	     opts: 更新的条件
func (obj *UsersDAO) UpdateByOption(users *Users, opts ...Option) (rowsAffected int64, err error) {
	obj.setIsDefaultColumns(false)
	tx := obj.prepare(opts...).Updates(users)
	return tx.RowsAffected, tx.Error
}

// --- 表中的字段作为 option 条件 -END ---

// --- 单个字段作为查询条件 ---

// GetFromID 通过单个 id(主键) 字段值,获取单条记录
func (obj *UsersDAO) GetFromID(id int64) (result *Users, err error) {
	result, err = obj.GetByOption(obj.WithID(id))
	return
}

// GetsFromID 通过多个 id(主键) 字段值,获取多条记录
func (obj *UsersDAO) GetsFromID(ids []int64) (results []*Users, err error) {
	results, err = obj.GetListByOption(obj.WithIDs(ids))
	return
}
...

// --- 单个字段作为查询条件 -END ---

// --- 通过索引(唯一索引(主键、唯一索引、唯一复合索引)、非唯一索引(普通索引))作为查询条件 ---

// FetchByPrimaryKey 通过 id 字段值,获取单条记录
func (obj *UsersDAO) FetchByPrimaryKey(id int64) (result *Users, err error) {
	result, err = obj.GetByOption(obj.WithID(id))
	return
}

// FetchUniqueByCardNo 通过 card_no 字段值,获取单条记录
func (obj *UsersDAO) FetchUniqueByCardNo(cardNo string) (result *Users, err error) {
	result, err = obj.GetByOption(obj.WithCardNo(cardNo))
	return
}

// FetchUniqueIndexByUnqNameCard 通过 name, card_no 字段值,获取单条记录
func (obj *UsersDAO) FetchUniqueIndexByUnqNameCard(name *string, cardNo string) (result *Users, err error) {
	result, err = obj.GetByOption(
		obj.WithName(name),
		obj.WithCardNo(cardNo))
	return
}

// FetchIndexByAge 通过 age 字段值,获取多条记录
func (obj *UsersDAO) FetchIndexByAge(age int64) (results []*Users, err error) {
	results, err = obj.GetListByOption(obj.WithAge(age))
	return
}

// --- 通过索引(唯一索引(主键、唯一索引、唯一复合索引)、非唯一索引(普通索引))作为查询条件 -END ---

四、注意

零值:0、‘’、false

(一)更新

当通过表模型结构体更新数据时,

  • GORM Updates() 方法只会更新非零字段。该工具底层就是用了这个方法,如果您想确保指定字段被更新,你应该使用 Select 更新选定字段、或者允许为零值的字段设置为指针、或使用 map 来完成更新操作

建议:工具会根据是否允许为空,判断允许为空则设置为指针,反之不设置;如果表设计是不允许为空,但是有存在零值,只能手动改为指针

  • GORM Save() 方法会保存所有的字段,即使字段是零值

(二)查询

当使用表模型结构体作为条件查询时,GORM 只会查询非零值字段。这意味着如果您的字段值为 0、‘’、false 或其他零值,该字段不会被用于构建查询条件。
但通过该工具生成的DAO层WithXxxWithXxxs作为条件则可以忽略这个,因为底层是用 map

(三)创建时间/创建时间

CreatedAt/UpdatedAt:

  • 创建数据时:CreatedAt/UpdatedAt:设置非零值时覆盖,为零值时会自动生成
  • 更新数据时:CreatedAt 不变;UpdatedAt 自动更新为当前时间戳

五、总结

如果你是一个Golang开发者,并且在使用 gorm 进行数据库操作,那么gormstruct绝对是你的必备工具,它可以帮助开发者根据表名生成表结构体和数据操作方法,提高开发效率。

如果觉得哪些功能需要改进的欢迎留言,最近还发现一个不错的学习网站推荐给大家 itgogogo.cn , 内容丰富,收集了很多学习资料和面试指南。

  • 49
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皇子谈技术

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值