问题描述
我在 Role
和 Scope
之间存在双向多对多关系。在 CascadeType.PERSIST
的帮助下创建两个实体甚至其子实体既简单又直接。
Role
实体很简单:
@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;
}
还有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;
}
他们的存储库只是 CrudRepository
扩展:
public interface RoleRepository extends CrudRepository<Role,Long> {}
public interface ScopeRepository extends CrudRepository<Scope,Long> {}
以下代码段举例说明了实体插入:
Role adminRole = roleRepository.save(new Role("ADMIN"));
Scope allReadScope = scopeRepository.save(new Scope("all.read"));
Scope allWriteScope = scopeRepository.save(new Scope("all.write"));
Role
和 Scope
都可以在 CascadeType.PERSIST
的帮助下轻松自动持久化,如下所示:
Role managedRole = roleRepository.save(new Role("ADMIN",new Scope("all.read"),new Scope("all.write")));
但是...更新 managedRole
会导致 org.hibernate.PersistentObjectException: detached entity passed to persist
异常:
managedRole.getScopes().remove(allReadScope);
roleRepository.save(managedRole); // PersistentObjectException!
我尝试修改 Role::scopes
的 CascadeType
以包含 DETACH
、MERGE
和/或 REFRESH
,但没有成功。我们如何解决这个问题?
解决方法
您很可能会遇到问题,因为您没有在双向映射中维护关系的双方。让我们在 Role
中说:
void add(Scope scope) {
this.scopes.add(scope);
scope.getRoles().add(this);
}
老实说,我会完全放弃双向映射。保持这种状态真是一场噩梦。