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

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

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

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

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

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

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

Согласно Hibernate Docs, dynamicUpdate аннотация делает именно это

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

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

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

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

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


person Jeremy S.    schedule 22.09.2011    source источник
comment
вы можете использовать динамическое обновление, чтобы избежать появления в SQL свойств, которые не были обновлены, но обычно рекомендуется использовать этот параметр только в том случае, если у объекта слишком много свойств (столбцы > 50) [ссылка: Java Persistence with Hibernate 2006 edition]. @hvgotcodes правильно указывает, что вам не нужно сопоставлять поля, если они никогда не будут сохранены.   -  person frictionlesspulley    schedule 22.09.2011


Ответы (3)


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

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

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

person gkamal    schedule 22.09.2011
comment
вести меня в правильном направлении. Лучше всего загрузить существующий объект и соответствующим образом обновить этот объект. У Джексона даже есть поведение по умолчанию для этого wiki.fasterxml.com/JacksonFeatureUpdateValue. - person Jeremy S.; 29.09.2011
comment
У меня нет нулевого значения в моей БД. Таким образом, никто никогда не будет явно обнулять что-либо. Есть ли другое решение для меня? @gkamal - person Ismail Yavuz; 19.08.2015

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

  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 из базы данных и меняю поле методом getNotNull, затем обновляю объект.

описание на китайском языке

person Acceml    schedule 08.01.2016

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

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.

person Xstarz    schedule 20.08.2019