4

In a db, I have User and Role entities. The share a many-to-many relation as a Role entity can be assigned to multiple User entities and on the other hand a User entity can be assigned to multiple Role entities.

My entity classes look like this

UserEntity

@Entity
public class UserEntity implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    @Column(unique = true, nullable = false)
    private String username;
    @ManyToMany
    private Set<RoleEntity> roles;

    ...
}

RoleEntity

@Entity
public class RoleEntity implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    @Column(unique = true, nullable = false)
    private String name;
    @ManyToMany(mappedBy = "roles")
    private Set<UserEntity> users;

    ...
}

With this configuration I am able to map the entities with each other. I am also able to delete a User entity. But I am not able to delete a Role entity as long as a relation exists.

If I add cascade = CascadeType.REMOVE the Rolegets deleted, but with it the User too of course.

To only way to get this working currently is to define a @JoinTable on both sides. But this seems more like a workaround. What am I doing wrong? As this is a regular use case, there got to be solution to this, although I haven found it yet...

Herr Derb
  • 4,977
  • 5
  • 34
  • 62
  • Did you check how your mapping looks in the database? If I remember correctly if you don't add @JoinTable what actually happens in the database is two join tables which hibernate somehow manages. That could cause you some problems down the road. – Deltharis Nov 30 '17 at 14:47
  • I don't know about the two tables. The JPA specification does state that there should be only one table: [JavaPersistence](http://download.oracle.com/otn-pub/jcp/persistence-2_1-fr-eval-spec/JavaPersistence.pdf?AuthParam=1512049284_a44e3e650d5915cfca02be3f5536609a) – Herr Derb Nov 30 '17 at 15:10

1 Answers1

1

You need the join table, it's not a work around. Remember you are mapping your object oriented model to a relational model. The only way to express many-to-many relationship in the relational model is defining a @JoinTable.

UPDATE: Adding comment in the answer
You sould define the @JoinTable just in one entity, for example UserEntity and mappedBy="roles" in RolesEntity inherits the definitions of @JoinColumn and @JoinTable names.

Then you need to define the cascade operations you want to perform in both sides of the relationship.

In RoleEntity

@ManyToMany(mappedBy = "roles")
private Set<UserEntity> users;

In UserEntity

@ManyToMany
@JoinTable(...)
private Set<RoleEntity> roles;
Rafael Guillen
  • 1,343
  • 10
  • 25
  • What I don't like on this approach is, that I'll have double definitions. Another thing, which I just have seen is the `@PreRemove` tag. I add a `PreRemove` method to the `Role` entity in which I remove the role from all its `User` it works too. The benefit to the `@JoinTable` is, that it looks slicker and I don't have any double definitions. – Herr Derb Nov 30 '17 at 14:43
  • What do you mean by double definitions? `mappedBy` is intended to inherit the relationship definition in the other entity. – Rafael Guillen Nov 30 '17 at 14:51
  • Sorry my bad. We currently have a custom naming of the `@JoinTable` which then needs to be declared on both sides of course. – Herr Derb Nov 30 '17 at 15:12
  • Why?? You sould define the `@JoinTable` just in one entity, for example `UserEntity` and `mappedBy="roles"` in `RolesEntity` inherits the definitions of `@JoinColumn` and @JoinTable names. – Rafael Guillen Nov 30 '17 at 15:18
  • Wait, this way I'm getting the constrain exception again, when I try to delete a `Role`that has relations to a `User` – Herr Derb Nov 30 '17 at 15:34
  • Check this: https://stackoverflow.com/questions/1082095/how-to-remove-entity-with-manytomany-relationship-in-jpa-and-corresponding-join and this: https://stackoverflow.com/questions/14585836/hibernate-many-to-many-cascading-delete – Rafael Guillen Nov 30 '17 at 19:43