我有一个包含以下字段的Person类 -
id,hashedId,description
id是序列生成的主键,hashedId为非空。
我执行以下操作:
- session.saveOrUpdate(人)
- person.setHashedId(散列(person.getId()))
醇>
ID在数据库中自动生成。当我这样做时,我不应该只期待2个陈述
- 选择以获取下一个序列ID(人员ID)
- 插入以插入人事记录?
醇>
但是,它正在尝试在第1步之后(在最终事务提交期间,当然)使用null hashedId - 我得到一个约束违规错误--HashedId不能为空。
答案 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推断出来。
希望这有帮助。