如何防止Hibernate更新NULL值

时间:2011-09-22 15:41:44

标签: hibernate null hibernate-mapping hibernate-annotations

保存hibernate对象时,hibernate中是否存在设置为忽略空值的设置?

注意
在我的例子中,我通过Jackson将JSON反序列化为Hibernate Pojo。

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   并且只包含列,其值不为空

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

如果你通过dynamic-update在XML中定义它,那么有趣的是,文档没有提到NULL值的数据。

  

dynamic-update(可选 - 默认为false):
指定UPDATE SQL应为>在运行时生成,只能包含值已更改的列。

由于我同时使用注释 AND xml配置,hibernate似乎忽略了我的dynamicUpdate=true注释。

3 个答案:

答案 0 :(得分:12)

首先应使用DB中的主键加载对象,然后在其上复制或反序列化JSON。

hibernate无法确定具有值null的属性是否已显式设置为该值,或者是否已将其排除。

如果是插入,则dynamic-insert = true应该有效。

答案 1 :(得分:0)

我已经搜索了很多关于此的内容,但对我来说没有解决方案。所以,我使用了一个不优雅的解决方案来覆盖它。

  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。 我从db获得tmp Obejct,并按方法getNotNull更改字段,然后更新对象。

a Chinese description edition

答案 2 :(得分:0)

我遇到了这个问题,并且做了一个变通办法来帮助自己解决这个问题。可能有点丑陋,但可能对您也很好。如果有人觉得有调整,可以随时添加。请注意,解决方法是针对有效的实体类,并且其某些字段包含可为空的属性。这样做的好处是可以减少查询数量。

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且字段为:userIduserNameuserAge的实体; getUpdateJPQL(user, userId, 2)的结果查询应为update User t set t.userName = 'value1', t.userAge = 'value2' where t.userId = 2 请注意,您可以在@JsonIgnore字段上使用userId之类的json批注,以在反序列化(即在生成的查询中)中将其排除。 然后,您可以使用entityManager或休眠会话运行查询。