Spring Data:管理双向多对多关系

问题描述

我在 RoleScope 之间存在双向多对多关系。在 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"));

RoleScope 都可以在 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::scopesCascadeType 以包含 DETACHMERGE 和/或 REFRESH,但没有成功。我们如何解决这个问题?

解决方法

您很可能会遇到问题,因为您没有在双向映射中维护关系的双方。让我们在 Role 中说:

void add(Scope scope) {
   this.scopes.add(scope);
   scope.getRoles().add(this);
}

老实说,我会完全放弃双向映射。保持这种状态真是一场噩梦。