Hibernate批处理操作无法按预期工作

时间:2010-12-03 01:35:02

标签: database hibernate postgresql orm

我有一个包含以下字段的Person类 -

  

id,hashedId,description

id是序列生成的主键,hashedId为非空。

我执行以下操作:

  
      
  1. session.saveOrUpdate(人)
  2.   
  3. person.setHashedId(散列(person.getId()))
  4.   

ID在数据库中自动生成。当我这样做时,我不应该只期待2个陈述

  
      
  1. 选择以获取下一个序列ID(人员ID)
  2.   
  3. 插入以插入人事记录?
  4.   

但是,它正在尝试在第1步之后(在最终事务提交期间,当然)使用null hashedId - 我得到一个约束违规错误--HashedId不能为空。

3 个答案:

答案 0 :(得分:2)

当您调用Session.save()或类似内容时,Hibernate将立即生成ID并执行插入操作,而不是简单地将其排队以便稍后保存。因此,在插入元素之前,元素的ID没有间隙。对于“身份”ID生成策略,无论如何都完全不可能将它们分开......

根据我的经验,处理这种情况的最安全和最简单的方法是使用Interceptor(或者可能是EventListener?)来捕获正在插入的实体,并且在未设置的情况下使用hashedId属性,并在保存之前生成它。这有点不愉快,但恕我直言,比将ID生成拉入应用程序代码更好。

以下是我生成新Ticket实体的'reference'属性(使用Interceptor)的示例:

public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames,
    Type[] types) {
    boolean changed = super.onSave(entity, id, state, propertyNames, types);

    if (entity instanceof Ticket) {
        for (int i = 0; i < propertyNames.length; i++) {
            if (propertyNames[i].equals("reference") && state[i] == null) {
                state[i] = generateTicketReference((Integer) id);
                changed = true;
            }
        }
    }

    return changed;
}

答案 1 :(得分:1)

Hibernate正在做正确的事:-)见http://docs.jboss.org/hibernate/core/3.3/reference/en/html/mapping.html#mapping-declaration-id,“5.1.4.4。标识列和序列”

那是因为如果它由DB生成,Hibernate不知道ID。而且,由于您调用了序列,因此ID并未真正分配给记录。因此,您应该让Hibernate保存记录并检索记录的实际ID,或者您应该使用Hibernate生成的ID(如hilo)(或自己生成,生成器类型为“已分配”)。

答案 2 :(得分:0)

HashedId字段是从ID中派生出来的,对吧?基于廉价的功能,我假设?那么在这种情况下你真的需要在数据库中保留该字段吗?你在查询中直接使用它吗? 难道你不能让getHashedId()方法总是返回hash(this.id)吗?这样,您就不会在数据库中拥有hashedId字段,也不必管理它 - 因为它只是根据id推断出来。

希望这有帮助。