【问题标题】:Spring Data: managing a bidirectional many-to-many relationshipSpring Data:管理双向多对多关系
【发布时间】:2021-04-07 12:07:32
【问题描述】:

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> {}

下面的 sn-p 举例说明了实体的插入:

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,但没有成功。我们如何解决这个问题?

【问题讨论】:

  • 请发布完整的堆栈跟踪
  • 对不起,Jens,但是为什么? Stacktrace 显示了一堆毫无意义的函数调用。问题在于导致上述异常的最新函数调用。

标签: java postgresql hibernate spring-data-jpa many-to-many


【解决方案1】:

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

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

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

【讨论】:

  • 它实际上是维护的,为了简洁我只是省略了它。我知道这很痛苦,但这是我发现自动创建删除级联的唯一方法(在scope 删除时,也删除role_scopes,如果有的话)。
  • 在多对多中小心使用 CascadeType.REMOVE -- 将它用于scope,您将按照您所说的scoperole_scopesrole 删除。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-28
  • 2023-01-02
  • 1970-01-01
  • 2017-11-11
  • 1970-01-01
  • 1970-01-01
  • 2015-09-11
相关资源
最近更新 更多