I have a bidirectional many-to-many relationship between a Role
and Scope
. Creating both entities and even their childs with the help of CascadeType.PERSIST
is easy and straightforward.
The Role
entity is simples as that:
@Entity
@Table(uniqueConstraints = @UniqueConstraint(name = "role_name", columnNames = "name"))
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST, mappedBy = "roles")
private Set<Scope> scopes;
}
And the Scope
:
@Entity
@Table(uniqueConstraints = @UniqueConstraint(name = "scope_name", columnNames = "name"))
public class Scope {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
@JoinTable(name = "role_scopes", joinColumns = @JoinColumn(name = "scope_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
@ManyToMany(cascade = CascadeType.REMOVE)
private Set<Role> roles;
}
Their repositories are simply CrudRepository
extensions:
public interface RoleRepository extends CrudRepository<Role, Long> {}
public interface ScopeRepository extends CrudRepository<Scope, Long> {}
The following snippet exemplifies the entities insertion:
Role adminRole = roleRepository.save(new Role("ADMIN"));
Scope allReadScope = scopeRepository.save(new Scope("all.read"));
Scope allWriteScope = scopeRepository.save(new Scope("all.write"));
Role
and Scope
can be both automatically easily persisted with the help of the CascadeType.PERSIST
, as follows:
Role managedRole = roleRepository.save(new Role("ADMIN", new Scope("all.read"), new Scope("all.write")));
However... Updating managedRole
leads to org.hibernate.PersistentObjectException: detached entity passed to persist
exception:
managedRole.getScopes().remove(allReadScope);
roleRepository.save(managedRole); // PersistentObjectException!
I tried modifying the Role::scopes
's CascadeType
to also include DETACH
, MERGE
and/or REFRESH
with no success. How do we get around this?
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…