• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    gorm update传入struct对象,零值字段不更新的解决方案

    使用gorm的update接口,出现如果字段为零值

    则不会生成字段的更新语句

    // Update update attributes with callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
    // WARNING when update with struct, GORM will not update fields that with zero value
    func (s *DB) Update(attrs ...interface{}) *DB {
     return s.Updates(toSearchableMap(attrs...), true)
    }

    如:

    type AA struct {
     ID             int       `gorm:"primary_key" json:" - "`            //主键id
        Code1       string   
     Code2     string                         
    }

    如果

    a :=AA{
        ID:1,
        Code1:1,
        Code2:0
    }

    则产生的SQL语句将不包含Code2更新语句,

    update aa set Code1 =1 where id =1;

    出现该问题的原因在于

    使用stuct类型对象作为参数时,struct会首先转化为map对象,然后再生成SQL语句,但是转化为map的过程中,对于零值字段是忽略的

    // assignUpdatingAttributesCallback assign updating attributes to model
    func assignUpdatingAttributesCallback(scope *Scope) {
    	if attrs, ok := scope.InstanceGet("gorm:update_interface"); ok {
    		if updateMaps, hasUpdate := scope.updatedAttrsWithValues(attrs); hasUpdate {
    			scope.InstanceSet("gorm:update_attrs", updateMaps)
    		} else {
    			scope.SkipLeft()
    		}
    	}
    } 
    func (scope *Scope) updatedAttrsWithValues(value interface{}) (results map[string]interface{}, hasUpdate bool) {
    	if scope.IndirectValue().Kind() != reflect.Struct {
    		return convertInterfaceToMap(value, false, scope.db), true
    	}
     
    	results = map[string]interface{}{}
     
    	for key, value := range convertInterfaceToMap(value, true, scope.db) {
    		if field, ok := scope.FieldByName(key); ok  scope.changeableField(field) {
    			if _, ok := value.(*SqlExpr); ok {
    				hasUpdate = true
    				results[field.DBName] = value
    			} else {
    				err := field.Set(value)
    				if field.IsNormal  !field.IsIgnored {
    					hasUpdate = true
    					if err == ErrUnaddressable {
    						results[field.DBName] = value
    					} else {
    						results[field.DBName] = field.Field.Interface()
    					}
    				}
    			}
    		}
    	}
    	return
    }  
    func convertInterfaceToMap(values interface{}, withIgnoredField bool, db *DB) map[string]interface{} {
    	var attrs = map[string]interface{}{}
     
    	switch value := values.(type) {
    	case map[string]interface{}:
    		return value
    	case []interface{}:
    		for _, v := range value {
    			for key, value := range convertInterfaceToMap(v, withIgnoredField, db) {
    				attrs[key] = value
    			}
    		}
    	case interface{}:
    		reflectValue := reflect.ValueOf(values)
     
    		switch reflectValue.Kind() {
    		case reflect.Map:
    			for _, key := range reflectValue.MapKeys() {
    				attrs[ToColumnName(key.Interface().(string))] = reflectValue.MapIndex(key).Interface()
    			}
    		default:
    			for _, field := range (Scope{Value: values, db: db}).Fields() {
    				if !field.IsBlank  (withIgnoredField || !field.IsIgnored) {
    					//只有非零值才更新
    					attrs[field.DBName] = field.Field.Interface()
    				}
    			}
    		}
    	}
    	return attrs
    }

    为了更新零值字段,则需要修改gorm库,我们这里添加一个FORCE标识字段必须更新

    type AA struct {
     ID             int       `gorm:"primary_key" json:" - "`            //主键id
        Code1       string    `gorm:"force"`
     Code2     string    `gorm:"force"`                       
    }

    修改Sope的Fields函数,对于有FORCE标签的字段,IsBlank直接设置为fasle

    // Fields get value's fields
    //通过反射获取field的值
    func (scope *Scope) Fields() []*Field {
    	if scope.fields == nil {
    		var (
    			fields             []*Field
    			indirectScopeValue = scope.IndirectValue()
    			isStruct           = indirectScopeValue.Kind() == reflect.Struct
    		)
    		// 解析结构体
    		for _, structField := range scope.GetModelStruct().StructFields {
    			if isStruct {
    				fieldValue := indirectScopeValue
    				// 一般只有一个字段名吧?????
    				for _, name := range structField.Names {
    					if fieldValue.Kind() == reflect.Ptr  fieldValue.IsNil() {
    						// 处理数组
    						fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
    					}
    					//
    					fieldValue = reflect.Indirect(fieldValue).FieldByName(name)
    				}
     
    				//有force代表强制更新
    				_, ok := structField.TagSettingsGet("FORCE")
    				fields = append(fields, Field{StructField: structField, Field: fieldValue, IsBlank: isBlank(fieldValue)  !ok})
    				//如果不是struct,则返回空,因为原生没有字段这个说法
    			} else {
    				fields = append(fields, Field{StructField: structField, IsBlank: true})
    			}
    		}
    		scope.fields = fields
    	} 
    	return *scope.fields
    }

    补充:Gorm 自动update操作自动过滤0和 “ “

    gorm会自动过滤结构体的0 和" "

    type CrmUserTableColumns struct {
    	Id                        int64  `gorm:"column:ids"`
    	Name                      string `gorm:"column:xxx"`
    	Account                   string `gorm:"column:xxx"`
    	Password                  string `gorm:"column:xxx"`
    	State                     int64  `gorm:"column:state"`
    	BusinessId                int64  `gorm:"column:business_id"`
    	DepartmentId              int64  `gorm:"column:department_id"`
    	...
    }
    func (u *CrmUserTableColumns) TableName() string {
    	return "crm_user"
    }
    field := map[string]interface{}{
    		"business_id":   data.BusinessId,
    		"state":         data.State,
    		"department_id": data.DepartmentId,
    	}
    	whereSql = "account = ?"
    updates := dbMasterClient.
    		//Debug().
    		Model(CrmUserTableColumns{}).
    		Where(whereSql, whereCase).
    		Updates(field)
    	RowsAffected = updates.RowsAffected
    	return
    

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。

    您可能感兴趣的文章:
    • gorm操作MySql数据库的方法
    • Go基于GORM 获取当前请求所执行的 SQL 信息(思路详解)
    • Golang 使用gorm添加数据库排他锁,for update
    • golang Gorm与数据库完整性约束详解
    • golang gorm 结构体的表字段缺省值设置方式
    • golang gorm 计算字段和获取sum()值的实现
    • gorm FirstOrCreate和受影响的行数实例
    • 解决Go gorm踩过的坑
    上一篇:一文完全掌握 Go math/rand(源码解析)
    下一篇:go如何删除字符串中的部分字符
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    gorm update传入struct对象,零值字段不更新的解决方案 gorm,update,传入,struct,对象,