Метод обновления не обновляет нулевое значение
Исходный вопрос
При использовании
Update
в GORM новые данные не сохраняются. т.е. я хочу установить
bool
из
true
к
false
, но это остается верным даже после
Update
метод.
В описании метода есть предупреждение: "ПРЕДУПРЕЖДЕНИЕ при обновлении с помощью структуры GORM не будет обновлять поля с нулевым значением"
Поскольку я использую структуру для обновления и
false
нулевое значение
bool
, это кажется ожидаемым поведением, но я не вижу причин, почему это нужно делать и как это преодолеть.
func UpdateData(c *fiber.Ctx) error {
db := database.DBConn
data := new([]entities.Data)
if err := c.BodyParser(&data); err != nil {
return err
}
db.Update(&data)
return c.JSON(data)
}
Резюме решения
Во-первых, как было предложено, я не учел
new
ключевое слово при создании экземпляров структур. Затем я использовал вспомогательную функцию ( отсюда) для преобразования структуры в карту, сохраняя псевдоним json в качестве ключей:
// StructToMap Converts a struct to a map while maintaining the json alias as keys
func StructToMap(obj interface{}) (newMap map[string]interface{}, err error) {
data, err := json.Marshal(obj)
if err != nil {
return
}
err = json.Unmarshal(data, &newMap) // Convert to a map
return
}
Затем я перебираю каждый элемент в срезе данных, чтобы преобразовать его и обновить один за другим:
func UpdateData(c *fiber.Ctx) error {
db := database.DBConn
data := []entities.Dard{}
if err := c.BodyParser(&data); err != nil {
return err
}
for _, record := range data {
mappedData, _ := StructToMap(record)
db.Model(&entities.Data{}).Update(mappedData)
}
return c.JSON(data)
}
* Обработка ошибок в этом примере явно сокращена.
2 ответа
Из официального документа
ПРИМЕЧАНИЕ При обновлении с помощью структуры GORM будет обновлять только ненулевые поля, вы можете использовать карту для обновления атрибутов или использовать Выбрать, чтобы указать поля для обновления.
Так что используйте
map[string]interface{}
также обновить ненулевые поля. Пример:
db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})
Поскольку у вас уже есть структура, вы можете преобразовать
struct
в
map[string]interface{}
( См. Подробности о преобразовании), затем обновите. Другой способ - изменить тип поля как указатель.
Как по мне, все поля должны сохраняться по умолчанию, в том числе и с пустыми значениями (ведь как удалить значение поля из экземпляра модели?).
В фактической документации есть пример того, как включить обновление всех полей (относительно разрешений полей, например, поля только для создания не будут обновляться).
// Select all fields (select all fields include zero value fields)
db.Moodel(&user).Select("*").Updates(User{Name: "jinzhu", Role: "admin", Age: 0})