Golang中g(shù)orm無法將字段更新為空值
在使用gorm將一個(gè)字段更新為空的時(shí)候,發(fā)現(xiàn)并不生效,不了解具體什么原因,所以此時(shí)需要打開debug模式,查看原生SQL是如何執(zhí)行的。
type Student struct {
Model
Email string `form:"email" json:"email"`
Name string `form:"name" json:"name"`
}
func(c *Content) update(content Content) (err) {
err = db.Model(&Content{}).Debug().Where("id = ?", 123).Update(&content).Error
}查看日志便知,此時(shí)如果name為空字符串,那么update的sql語(yǔ)句中并不會(huì)set,后查閱,方知gorm對(duì)于空字符和0這種數(shù)據(jù),認(rèn)為是不需要處理的,所以。。。
遇到這個(gè)問題,有兩種解決方案:
A.更新傳值的時(shí)候通過map來指定;
B.修改gorm的源碼包,讓它支持自定義是否可以設(shè)置為空值;
上述兩種方案,第一種比較簡(jiǎn)單,不過感覺比較low,所以我選擇嘗試第二種。
當(dāng)然第二種,也有它的問題,比如被更新之后,得手動(dòng)去調(diào)整回來。
下面重點(diǎn)講解第二種方案的實(shí)施。
1、找到gorm包下的scope.go文件
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
}上面代碼表示我們傳遞過來的數(shù)據(jù)會(huì)被轉(zhuǎn)為map型,然后再進(jìn)行數(shù)據(jù)庫(kù)字段更新,這個(gè)代碼很簡(jiǎn)單,就是把滿足條件保存到map。
我們要解決的是空值能夠更新,則和field.IsBlank相關(guān)聯(lián),接著找到下一個(gè)方法;
// Fields get value's fields
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)
}
//判斷model中字段有沒有force字段,此處使用Force,是因?yàn)榻馕鰐ag時(shí),統(tǒng)一轉(zhuǎn)成了大寫
_, ok := structField.TagSettingsGet("FORCE")
//如果字段為空值,且字段存在則設(shè)定為false
fields = append(fields, &Field{StructField: structField, Field: fieldValue, IsBlank: isBlank(fieldValue) && !ok})
} else {
fields = append(fields, &Field{StructField: structField, IsBlank: true})
}
}
scope.fields = &fields
}
return *scope.fields
}注意上面帶注釋的兩行,作用就不再贅述了。
2、修改我們的model
type Student struct {
Model
Email string `gorm:"force" form:"email" json:"email"`
Name string `gorm:"force" form:"name" json:"name"`
}
func(c *Content) update(content Content) (err) {
err = db.Model(&Content{}).Debug().Where("id = ?", 123).Update(&content).Error
}此時(shí)執(zhí)行則順利完成,SQL語(yǔ)句也包含了所有字段。
3、你有沒有感到奇怪,為什么scope里面校驗(yàn)的是FORCE,而我在model中則定義的是force?
這就要說到另一個(gè)文件 gorm包下的 model_struct.go
func parseTagSetting(tags reflect.StructTag) map[string]string {
setting := map[string]string{}
for _, str := range []string{tags.Get("sql"), tags.Get("gorm")} {
if str == "" {
continue
}
tags := strings.Split(str, ";")
for _, value := range tags {
v := strings.Split(value, ":")
k := strings.TrimSpace(strings.ToUpper(v[0]))
if len(v) >= 2 {
setting[k] = strings.Join(v[1:], ":")
} else {
setting[k] = k
}
}
}
return setting
}這個(gè)方法表示將orm中定義的tag標(biāo)簽,全部解析并轉(zhuǎn)化為大寫。
到此這篇關(guān)于Golang中g(shù)orm無法將字段更新為空值的文章就介紹到這了,更多相關(guān)gorm 字段更新為空值內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Golang讀取toml配置文件的代碼實(shí)現(xiàn)
在開發(fā)過程中,配置文件是必不可少的一部分,它使我們能夠在不更改代碼的情況下更改應(yīng)用程序的行為,TOML是一種簡(jiǎn)單易讀的配置文件格式,本文將介紹如何使用Golang來讀取TOML配置文件,需要的朋友可以參考下2024-04-04
Go語(yǔ)言快速搭建一個(gè)API流式回復(fù)本地模擬接口
這篇文章主要為大家詳細(xì)介紹了如何使用Go語(yǔ)言快速搭建一個(gè)API流式回復(fù)本地模擬接口,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-12-12
Go 實(shí)現(xiàn)英尺和米的簡(jiǎn)單單位換算方式
這篇文章主要介紹了Go 實(shí)現(xiàn)英尺和米的簡(jiǎn)單單位換算方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-04-04
Golang中ringbuffer的實(shí)現(xiàn)與應(yīng)用場(chǎng)景詳解
ringbuffer因?yàn)樗軓?fù)用緩沖空間,通常用于網(wǎng)絡(luò)通信連接的讀寫,雖然市面上已經(jīng)有了go寫的諸多版本的ringbuffer組件,但還是自己造一個(gè)吧2023-06-06

