在我的应用程序中,我有这些Hibernate映射类型(一般情况):
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 Setrules = new HashSet (0); @OneToMany(cascade=CascadeType.ALL) @JoinColumn(name="ROLE_ID") public Set getRules() { return rules; } public void setRules(Set rules) { this.rules = rules; } }
所有课程都有equals() & hashCode()
覆盖.
我的应用程序允许调整角色(仅限系统管理员,不用担心),以及其他字段,允许创建新的角色规则.创建新规则时,我尝试创建一个新RoleRule
对象并将其插入角色的字段中rules
.我打电话session.update(role)
来将更改应用到数据库.
现在来了丑陋的部分...... Hibernate决定在关闭事务和刷新时执行以下操作:
将新规则插入数据库.优秀.
更新其他角色字段(不是集合).到现在为止还挺好.
更新现有规则,即使它们中没有任何更改.我可以忍受这个.
再次更新现有规则.这是来自日志的粘贴,包括自动注释:
/* delete one-to-many row Role.rules */ update ROLE_RULE set ROLE_ID=null where ROLE_ID=? and ROLE_RULE_ID=?
当然,所有字段都不为空,并且此操作无法完成.
任何人都可以尝试解释为什么Hibernate会这样做??? 更重要的是,我如何解决这个问题?
编辑:我很确定它与映射有关,然后我的老板,一时兴起,删除了equals()
和hashCode()
这两类,其中重新使用Eclipse,而这个神秘解决了这个问题.
我对我的问题仍然很好奇.任何人都可以建议为什么Hibernate会这样做?
我通常使用两种方法来更新Hibernate中的集合(一对多的许多方面).蛮力方式是清除集合,在父节点上调用save,然后调用flush.然后添加所有集合成员并再次调用父节点.这将删除所有,然后插入所有.中间的刷新是关键,因为它强制删除在插入之前发生.最好只对小型集合使用此方法,因为它会重新插入所有这些方法.
第二种方式更难编码,但效率更高.循环遍历新的子集并手动修改仍然存在的子集,删除不存在的子集,然后添加新的子节点.在伪代码中将是:
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
我已经在Hibernate论坛上搜索了好几个小时,试图找到解决这个问题的正确方法.您应该能够只更新您的集合以使其准确然后保存父节点,但是正如您所知,Hibernate尝试在删除它们之前将子节点从父节点分离,并且如果外键不为null,则它将失败.
请参阅" 在Java中覆盖equals和hashCode "这一问题的答案.
它解释了如何覆盖equals和hashCode方法,这似乎是你的问题,因为它在重写之后起作用.
错误地覆盖它们会导致hibernate删除您的集合并重新插入它们.(因为哈希键在地图中用作键)