【问题标题】:How can I prevent Hibernate from updating NULL values如何防止 Hibernate 更新 NULL 值
【发布时间】:2011-11-22 23:18:12
【问题描述】:

在保存休眠对象时,休眠中是否有设置忽略空值属性?

注意
就我而言,我通过 Jackson 将 JSON 反序列化为 Hibernate Pojo。

JSON 只包含 Pojo 的一些字段。如果我保存 Pojo,则不在 JSON 中的字段在 Pojo 中为 null 并休眠更新它们。

我遇到了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

如果您通过dynamic-update 在 XML 中定义它就够有趣了,文档中没有提到 NULL 值的处理。

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

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

【问题讨论】:

  • 您可以使用动态更新来避免 SQL 中出现尚未更新的属性,但通常建议仅在实体具有过多属性时使用此设置(列 > 50)[参考: Java Persistence with Hibernate 2006 edition]。 @hvgotcodes 正确地指出,如果字段永远不会被持久化,您不必映射字段。

标签: hibernate null hibernate-mapping hibernate-annotations


【解决方案1】:

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

hibernate 无法确定值为 null 的属性是否已显式设置为该值或已被排除。

如果是插入,那么 dynamic-insert=true 应该可以工作。

【讨论】:

  • 引导我走向正确的方向。最好是加载现有对象并相应地更新此对象。杰克逊甚至对 wiki.fasterxml.com/JacksonFeatureUpdateValue 有一个默认行为
  • 我的数据库中没有任何空值。因此,没有人永远不会明确地将任何内容设置为空。我还有其他解决方案吗? @gkamal
【解决方案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。 我从db得到一个tmp Obejct,通过getNotNull方法改变字段,然后更新Object。

a Chinese description edition

【讨论】:

    【解决方案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,字段为:userIduserName & userAgegetUpdateJPQL(user, userId, 2)的结果查询应该是update User t set t.userName = 'value1', t.userAge = 'value2' where t.userId = 2 请注意,您可以在 userId 字段上使用 json 注释(如 @JsonIgnore)在反序列化(即生成的查询)中将其排除。 然后,您可以使用 entityManager 或休眠会话运行查询。

    【讨论】:

      猜你喜欢
      • 2021-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-26
      • 1970-01-01
      • 2011-02-28
      • 2016-10-21
      • 1970-01-01
      相关资源
      最近更新 更多