Как я могу запретить Hibernate обновлять значения NULL

Есть ли параметр в спящем режиме для игнорировать нулевые значения свойств при сохранении объекта спящего режима?

ПРИМЕЧАНИЕ
В моем случае я де-сериализую JSON в Hibernate Pojo через Jackson.

JSON содержит только некоторые поля Pojo. Если я сохраню Pojo, поля, которые не были в JSON, равны нулю в Pojo и hibernate, ОБНОВЛЯЕТ их.

Я прошел через настройку updateable=false, но это не 100% -ное решение. http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-mapping-property

Может быть, у кого-то есть другая идея...

ПРИМЕЧАНИЕ 2:

В соответствии с документами Hibernate dynamicUpdate аннотация делает именно это

dynamicInsert/dynamicUpdate (по умолчанию - false):
указывает, что INSERT/UPDATE SQL должен быть сгенерирован во время выполнения и содержат только столбцы , значения которых не равны null.

http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#mapping-declaration-class

Достаточно смешно, если вы определяете его в XML через dynamic-update, в документе не упоминается hanlding значений NULL.

dynamic-update (необязательно - по умолчанию - false):
указывает, что UPDATE SQL должен быть > сгенерирован во время выполнения и может содержать только те столбцы, значения которых изменены.

В связи с тем, что я использую как аннотации И xml конфигурации, hibernate, похоже, игнорирует аннотацию dynamicUpdate=true.

Ответы

Ответ 1

Сначала вы должны загрузить объект, используя первичный ключ из БД, а затем скопировать или десериализовать JSON поверх него.

Спящий режим не может определить, было ли свойство со значением null явно установлено на это значение или оно было исключено.

Если это вставка, то dynamic-insert = true должен работать.

Ответ 2

Я много рассказывал об этом, но для меня нет самого решения. Поэтому я использовал не изящное решение для его покрытия.

  public void setAccount(Account a) throws HibernateException {
    try {
        Account tmp = (Account) session.
                get(Account.class, a.getAccountId());
        tmp.setEmail(getNotNull(a.getEmail(), tmp.getEmail()));            
        ...
        tmp.setVersion(getNotNull(a.getVersion(), tmp.getVersion()));
        session.beginTransaction();
        session.update(tmp);
        session.getTransaction().commit();
    } catch (HibernateException e) {
        logger.error(e.toString());
        throw e;
    }
}

public static <T> T getNotNull(T a, T b) {
    return b != null && a != null && !a.equals(b) ? a : b;
}

Я получаю Object a, который содержит много полей. Это поле может быть null, но я не хочу обновлять их в mysql. Я получаю tmp Obejct из db и изменяю поле методом getNotNull, а затем обновляю объект.

китайская версия описания

Ответ 3

Я столкнулся с этой проблемой и сделал обходной путь, чтобы помочь себе в этом. Может быть немного некрасиво, но может работать и для вас. Будь добр, если кто-то посчитает, что это хорошо, чтобы добавить его. Обратите внимание, что обходной путь предназначен для допустимых классов сущностей, чьи некоторые поля включают в себя обнуляемые атрибуты. Преимущество этого метода в том, что оно уменьшает количество запросов.

public String getUpdateJPQL(Object obj, String column, Object value) throws JsonProcessingException, IOException {

//obj -> your entity class object
//column -> field name in the query clause
//value -> value of the field in the query clause

    ObjectMapper mapper = new ObjectMapper();
    String json = mapper.writeValueAsString(obj);
    Map<String, Object> map = mapper.readValue(json, Map.class);
    Map format = new HashMap();
    if (value instanceof String) {
        value = "'" + value + "'";
    }

    map.keySet()
            .forEach((str) -> {
                Object val = map.get(str);
                if (val != null) {
                    format.put("t.".concat(str), "'" + val + "'");
                }
            });
    String formatStr = format.toString();
    formatStr = formatStr.substring(1, formatStr.length() - 1);

    return "update " + obj.getClass()
            .getSimpleName() + " t set " + formatStr + " where " + column + " = " + value + "";

}

Пример: для типа объекта User с полями: userId, userName & userAge; запрос результата getUpdateJPQL(user, userId, 2) должен быть update User t set t.userName = 'value1', t.userAge = 'value2' where t.userId = 2 Обратите внимание, что вы можете использовать аннотации json, такие как @JsonIgnore в поле userId, чтобы исключить его при десериализации, т.е. в сгенерированном запросе. Затем вы можете выполнить свой запрос, используя entityManager или Hibernate.