为什么Hibernate尝试删除当我尝试更新/插入? [英] Why does Hibernate try to delete when I try to update/insert?

查看:84
本文介绍了为什么Hibernate尝试删除当我尝试更新/插入?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 类RoleRule {
私有的角色角色;
私人PermissionAwareEntity实体; //为其授予权限的hibernate映射实体
private PermissionType permissionType; //枚举

@ManyToOne
@JoinColumn(name =ROLE_ID)
public Role getRole(){
return role;
}
public void setRole(Role role){
this.role = role;
}

}

类角色{
private Set< RoleRule> rules = new HashSet< RoleRule>(0);

@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name =ROLE_ID)
public Set< RoleRule> getRules(){
返回规则;
}
public void setRules(Set< RoleRule> rules){
this.rules = rules;
}

}

所有类都有 equals()& hashCode()覆盖。



我的应用程序允许调整角色(仅由系统管理员操作,不用担心),以及其他字段允许创建新的角色规则。当创建新规则时,我尝试创建一个新的 RoleRule 对象,并将其插入到角色的规则字段中。我将 session.update(role)称为将更改应用于数据库。



现在出现了丑陋的部分。当关闭事务和刷新时,Hibernate决定执行以下操作:


  1. 将新规则插入到数据库中。非常好。

  2. 更新其他角色字段(而不是集合)。到目前为止这样好。

  3. 更新现有规则,即使它们中没有任何更改。我可以忍受这一点。

  4. 再次更新现有规则 。以下是日志中的一个粘贴,包括自动注释:



 / *删除一对多行Role.rules * / 
更新ROLE_RULE设置ROLE_ID = null其中ROLE_ID =?和ROLE_RULE_ID =?

当然,所有的字段都不为空,而且这个操作失败了。



任何人都可以尝试解释为什么Hibernate会这样做?更重要的是,我是如何解决这个问题的?



编辑:我确定这是与映射,然后是我的老板,随时随地在两个类中删除了 equals() hashCode() ,使用Eclipse重新创建它们,神秘地解决了这个问题。



尽管如此,我仍然很好奇我的问题。任何人都可以提出为什么Hibernate会这样做?

解决方案

我通常使用两种方法更新集合在Hibernate中是一对多)。蛮力的方法是清除集合,调用保存在父级上,然后调用flush。然后添加所有收集成员并再次调用保存在父项上。这将删除所有,然后插入全部。中间的冲洗是关键,因为它会在插入之前强制删除。最好只在小集合上使用这种方法,因为它重新插入了所有这些方法。第二种方法更难编码,但效率更高。你循环遍历新的一组孩子并手动修改那些仍然存在的孩子,删除那些没有的孩子,然后添加新的孩子。在伪代码中:

 将现有记录的列表复制到list_to_delete 
中形式
如果记录存在,则从list_to_delete
中删除它(基于equals()?key?)
更改用户可以输入的每个字段
如果记录不存在, t存在
将其添加到集合
结束为
为每个list_to_delete
删除它
结束为
保存

我在Hibernate论坛搜索了很多小时,试图找到正确的方法来解决这个问题。你应该能够更新你的集合来保证它的准确性,然后保存父对象,但正如你发现的那样,Hibernate会在删除它们之前尝试从父对象中分离子对象,如果外键不为null,它会将失败。


In my app I have these Hibernate-mapped types (general case):

class RoleRule {
  private Role role;
  private PermissionAwareEntity entity; // hibernate-mapped entity for which permission is granted
  private PermissionType permissionType; // enum

  @ManyToOne
  @JoinColumn(name = "ROLE_ID")
  public Role getRole() {
    return role;
  }
  public void setRole(Role role) {
    this.role = role;
  }

}

class Role {
  private Set<RoleRule> rules = new HashSet<RoleRule>(0);

  @OneToMany(cascade=CascadeType.ALL)
  @JoinColumn(name="ROLE_ID")
  public Set<RoleRule> getRules() {
    return rules;
  }
  public void setRules(Set<RoleRule> rules) {
    this.rules = rules;
  }

}

All classes have equals() & hashCode() overrides.

My application allows tweaking of roles (by sysadmins only, don't worry), and among other fields, allows creation of new role rules. When a new rule is created I try to create a new RoleRule object and insert it into the role's field rules. I call session.update(role) to apply the changes to the database.

Now comes the ugly part... Hibernate decides to do the following when closing the transaction and flushing:

  1. Insert the new rule into the database. Excellent.
  2. Update the other role fields (not collections). So far so good.
  3. Update the existing rules, even if nothing has changed in them. I can live with this.
  4. Update the existing rules again. Here's a paste from the log, including the automatic comment:

/* delete one-to-many row Role.rules */
update ROLE_RULE set ROLE_ID=null where ROLE_ID=? and ROLE_RULE_ID=?

Of course, all fields are not-null, and this operation fails spectacularly.

Can anyone try to explain why Hibernate would do this??? And even more important, how the frak do I get around this???

EDIT: I was so sure it was something to do with the mapping, and then my boss, on a whim, deleted the equals() and hashCode() in both classes, recreated them using Eclipse, and mysteriously this solved the problem.

I'm still very curious about my question though. Can anyone suggest why Hibernate would do this?

解决方案

I've generally used two methods of updating a collection (the many side of a one-to-many) in Hibernate. The brute force way is to clear the collection, call save on the parent, and then call flush. Then add all of the collection members back and call save on the parent again. This will delete all and then insert all. The flush in the middle is key because it forces the delete to happen before the insert. It's probably best to only use this method on small collections since it does re-insert all of them.

The second way is harder to code, but more efficient. You loop through the new set of children and manually modify the ones that are still there, delete the ones that aren't, and then add the new ones. In pseudo-code that would be:

copy the list of existing records to a list_to_delete
for each record from the form
   remove it from the list_to_delete
   if the record exists (based on equals()?  key?)
     change each field that the user can enter
   else if the record doesn't exist
     add it to the collection
end for
for each list_to_delete
  remove it
end for
save

I've searched the Hibernate forums for many hours trying to find the right way to solve this problem. You should be able to just update your collection to make it accurate and then save the parent, but as you've found out, Hibernate tries to detach the children from the parent before deleting them and if the foreign key is not-null, it will fail.

这篇关于为什么Hibernate尝试删除当我尝试更新/插入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆