简体   繁体   中英

Spring Data: managing a bidirectional many-to-many relationship

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?

Most likely you face the problem, because you don't maintain both sides of the relationship in the bidirectional mapping. Lets say in Role :

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

To be honest with you, I'd resign fully from bidirectional mapping. Maintaining this is a real nightmare.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM