Метод обновления не обновляет нулевое значение

Исходный вопрос

При использовании 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})
Другие вопросы по тегам