-
发生时间:2022-10-26
-
问题描述:同事在调试产线平台前端时,将「设备类型」某条记录的「备注」清空、提交,然后再次查询,发现「备注」并没有被清空。
-
原因分析:
- 在测试环境重复同事的操作,发现确实无法清空「备注」,但可以修改「备注」为任何非空的字符串。看来问题与「空字符串」有一定关系。
- 经过网上调查,在 stack overflow 发现一个知识点——当使用 struct 来更新数据库记录时,gorm 只会更新 struct 中取值为非零值的字段。
NOTE When update with struct, GORM will only update non-zero fields, you might want to use map to update attributes or use Select to specify fields to update.
- 由于我正是使用 struct 来更新的,因此空的「备注」字段直接被 gorm 无视了,导致「备注」的内容没被清空。
// UpdateOrCreate updates an entry if it exists, or creates it if it doesn't exist. func UpdateOrCreate(entry Modeler) error { entry.SetUpdateTime(time.Now()) id := entry.GetID() db := GetDatabaseConnection() if result := db.Model(entry).Where("id = ?", id).Updates(entry); result.Error != nil { logs.Errorf("db.Update(factory) error: %s. entry: %+v", result.Error, entry) return result.Error } else if result.RowsAffected == 0 { logs.Warnf("entry not found. Now we try to create it. entry: %+v", entry) if err := db.Create(entry).Error; err != nil { logs.Errorf("db.Create error: %s. entry: %+v", err, entry) return err } } return nil } -
解决方案:
- 如上所述,有两种解决方案:改用 map 数据结构,或使用
Select来指定需要更新的字段。 - 由于方案二对现有代码的改动更小,因此我最终选择了方案二,如下所示。
// UpdateOrCreate updates an entry if it exists, or creates it if it doesn't exist. func UpdateOrCreate(entry Modeler) error { entry.SetUpdateTime(time.Now()) id := entry.GetID() db := GetDatabaseConnection() // Use `Select` to select what we want to update, and use `Omit` to skip what we don't want to update. if result := db.Model(entry).Where("id = ?", id).Select("*").Omit("created_at").Updates(entry); result.Error != nil { logs.Errorf("db.Update(factory) error: %s. entry: %+v", result.Error, entry) return result.Error } else if result.RowsAffected == 0 { logs.Warnf("entry not found. Now we try to create it. entry: %+v", entry) if err := db.Create(entry).Error; err != nil { logs.Errorf("db.Create error: %s. entry: %+v", err, entry) return err } } return nil } - 如上所述,有两种解决方案:改用 map 数据结构,或使用
-
实施结果:采用上述方案后,在产线平台前端可以清空任意数据中的「备注」字段。
-
经验总结:
- 在 gorm 中使用 struct 来更新数据库记录时,默认不会更新其中的零值字段。编程时需要注意这个坑。