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:
- Insert the new rule into the database. Excellent.
- Update the other role fields (not collections). So far so good.
- Update the existing rules, even if nothing has changed in them. I can live with this.
- 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?