栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Go语言

go - gorm使用过程中遇到的问题和解决

Go语言 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

go - gorm使用过程中遇到的问题和解决

前言

考虑到gorm目前已经升级到了2.0版本, 且官方更新记录里罗列了若干升级后的优势, 故这里介绍的, 大部分都是基于gorm2.0

gorm1.0+ import的package为"github.com/jinzhu/gorm
gorm2.0 import的package为"gorm.io/gorm"

升级到2.0以后, 开发时console不输出执行的sql

在旧版本中, 是有以下方法去控制sql是否输出

// LogMode set log mode, `true` for detailed logs, `false` for no log, default, will only print error logs
func (s *DB) LogMode(enable bool) *DB {
	if enable {
		s.logMode = 2
	} else {
		s.logMode = 1
	}
	return s
}

但是升级到新版本后, 发现*DB不再有LogMode方法, 如果需要在console中输出执行的sql, 需要调整连接数据库时的gorm.Config,

	newLogger := logger.New(
		log.New(os.Stdout, "rn", log.LstdFlags), // io writer
		logger.Config{
			SlowThreshold:             200 * time.Millisecond, // 慢 SQL 阈值, 200ms
			LogLevel:                  logger.Info,            // 日志级别
			IgnoreRecordNotFoundError: true,                   // 忽略ErrRecordNotFound(记录未找到)错误
			Colorful:                  true,                   // 彩色打印
		},
	)

	DB, err = gorm.Open(mysql.New(mysql.Config{
		DSN: dsn,
		//更多mysql的配置可以到官方查看, 这里就不展开了
	}), &gorm.Config{
		Logger:                                   newLogger,
		DisableForeignKeyConstraintWhenMigrating: true,
		NamingStrategy: schema.NamingStrategy{
			SingularTable: true, // 使用单数表名,启用该选项后,`Student` 表将是`student`, 禁用则为`students`
			//TablePrefix:   "pre_", // 表名前缀,`User`表为`pre_users`
			//NameReplacer:  strings.NewReplacer("AbcID", "Abcid"), // 在转为数据库名称之前,使用NameReplacer更改结构/字段名称。
		},
	})

此外, 这里可以看到, 旧版本的db.SingularTable(true)也调整到gorm.Config里面了
还有旧版本对于表明前缀的handler也调整到gorm.Config里面了

	gorm.DefaultTableNameHandler = func(db *gorm.DB, defaultTableName string) string {
		return setting.DatabaseSetting.TablePrefix + defaultTableName
	}
时间默认值

当使用的gorm为 "github.com/jinzhu/gorm"时, 可通过以下方式, 实现插入数据前赋予默认值

db.Callback().Create().Replace("gorm:update_time_stamp", updateTimeStampWhileCreate)
func updateTimeStampWhileCreate(scope *gorm.Scope) {
	if !scope.HasError() {
		nowTime := time.Now()
		if createTimeField, ok := scope.FieldByName("CreateTime"); ok {
			if createTimeField.IsBlank {
				createTimeField.Set(nowTime)
			}
		}

		if updateTimeField, ok := scope.FieldByName("UpdateTime"); ok {
			if updateTimeField.IsBlank {
				updateTimeField.Set(nowTime)
			}
		}
	}
}

升级到 "gorm.io/gorm" 后, callback的参数不再是实体了, 而是DB, 故调整为:

	DB.Callback().Create().Before("gorm:create").Register("update_time_before_create", func(db *gorm.DB) {
		timeFieldsToInit := []string{"CreateTime", "UpdateTime"}
		for _, field := range timeFieldsToInit {
			if timeField := db .Statement.Schema.LookUpField(field); timeField != nil {
				fmt.Println(field, timeField)
				timeField.Set(db .Statement.ReflectValue, time.Now())
			}
		}
	})

如果Create单个数据的时候, 这样操作还是没问题的, 但是, 如果是执行批量操作, 这样明显就不行了, 需要在这里加个判断, 判断db .Statement.ReflectValue的类型

	DB.Callback().Create().Before("gorm:create").Register("update_create_time", func(db *gorm.DB) {
		timeFieldsToInit := []string{"CreateTime", "UpdateTime"}
		for _, field := range timeFieldsToInit {

			if timeField := db.Statement.Schema.LookUpField(field); timeField != nil {
				switch db.Statement.ReflectValue.Kind() {
				case reflect.Slice, reflect.Array:
					for i := 0; i < db.Statement.ReflectValue.Len(); i++ {
						timeField.Set(db.Statement.ReflectValue.Index(i), time.Now())
					}
				case reflect.Struct:
					timeField.Set(db.Statement.ReflectValue, time.Now())
				}
			}
		}
	})

但是这样写有个不好的地方是, 已经赋值了的会被覆盖掉, 故, 上面缺少对原值的判断, 需要加上:

	DB.Callback().Create().Before("gorm:create").Register("update_create_time", func(db *gorm.DB) {
		timeFieldsToInit := []string{"CreateTime", "UpdateTime"}
		for _, field := range timeFieldsToInit {

			if timeField := db.Statement.Schema.LookUpField(field); timeField != nil {
				switch db.Statement.ReflectValue.Kind() {
				case reflect.Slice, reflect.Array:
					for i := 0; i < db.Statement.ReflectValue.Len(); i++ {
						if _, isZero := timeField.ValueOf(db.Statement.ReflectValue.Index(i)); isZero {
							timeField.Set(db.Statement.ReflectValue.Index(i), time.Now())
						}
					}
				case reflect.Struct:
					if _, isZero := timeField.ValueOf(db.Statement.ReflectValue); isZero {
						timeField.Set(db.Statement.ReflectValue, time.Now())
					}
				}
			}
		}
	})

更多callback的使用, 可见: gorm-编写插件

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/965405.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号