简体   繁体   中英

How make both sides of many-to-many relation ships owner?

I have a class Group and a class User
where Group and User are many-to-many relation ship
If i change the groups of a user and save a user i want to update the groups
and vice versa where if i changed a user of a group and save the group i want the user to be updated
Do i have to set the mappedBy in both classes
Note : I am using eclipseLink

For a many-to-many relationship, you will need to update the relationship data on both sides in order to stay consistent.

Unfortunately there is no shortcut.

What you can do is to create a single method on either of the entities or a third class to encapsulate the consistent update.

Beware of infinite loops - do not implement the propagation to the other entity in both entity classes.

Roughly like this:

public class User
...
public void addGroup(Group g){
   groups.add(g);
   g.addUser(this);
}

or

public class Group
...
public void addUser(User u){
   users.add(u);
   u.addGroup(this);
}

I assume the presence of proper cascade settings on the relationship annotations.

There is a difference between owning a relation and a bidirectional reference . The former primarily concerns the layout of your database where the latter concerns your application logic. From your question, I assume that you want the latter. At the same time, it is generally recommendable that only one side of a relation owns a reference. You can easily create a bidirectional reference while keeping a clear collection owner by creating add and remove methods that enforce bidrection:

class Group {

  @ManyToMany
  private Collection<User> users = ... ;

  public void addUser(User user) {
    if(user != null && !users.contains(user)) {
      users.add(user)
      user.addGroup(this);
    }
  }

  public void removeUser(User user) {
    if(user != null && users.contains(user)) {
      users.remove(user)
      user.removeGroup(this);
    }
  }
}

class User {

  @ManyToMany(mappedBy="users")
  private Collection<Group> groups = ... ;

  public void addGroup(Group group) {
    if(group != null && !groups.contains(group)) {
      groups.add(group)
      group.addUser(this);
    }
  }

  public void removeGroup(Group group) {
    if(group != null && groups.contains(group)) {
      groups.remove(group)
      group.removeUser(this);
    }
  }
}

In this example, Group owns the relation what does however not affect the application logic. Be aware of the manipulation order in order to avoid infinite loops. Also, note that this code is not thread-safe.

I understand that for author it is a little bit late, but maybe it will be helpful for another readers.

You can achieve this by adding @JoinTable for both sides: (cascading you can add by your needs)

public class Group {
    ....

    @ManyToMany
    @JoinTable(
            name = "group_user", 
            joinColumns = @JoinColumn(name = "groups_id"),
            inverseJoinColumns = @JoinColumn(name = "users_id"))
    private List<User> users;
}
public class User {
    ....

    @ManyToMany
    @JoinTable(
            name = "group_user", 
            joinColumns = @JoinColumn(name = "users_id"),
            inverseJoinColumns = @JoinColumn(name = "groups_id"))
    private List<Group> groups;
}

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