JPA ManyToMany с дополнительным отношением ManyToMany - PullRequest
0 голосов
/ 19 сентября 2019

Мне нужно поддержать сценарий, который включает следующие объекты (с использованием JPA):

  1. Пользователь
  2. Аккаунт
  3. Роль

Пользователь может иметь несколько учетных записей, и учетная запись может совместно использоваться несколькими пользователями, на данный момент это стандартное отношение @ManyToMany.

Пользователь может иметь различный набор ролей для каждой учетной записи, роль можетбыть доступным для нескольких пользователей.

enter image description here

Я следовал этой практике , которая объясняет способ сопоставления многих смного ассоциаций с дополнительными столбцами, но я не уверен, что получаю его.

сущность UserAccount:

@Entity
@Table(name = "users_accounts")
public class UserAccount implements Serializable {

    @EmbeddedId
    private UserAccountId id;

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("userId")
    private User user;

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("accountId")
    private Account account;


    private UserAccount() {}

    public UserAccount(@NotNull User user, @NotNull Account account) {
        this.user = user;
        this.account = account;
        this.id = new UserAccountId(user.getId(), account.getId());
    }

    //Getters  Setters..

}

UserAccountId:

@Embeddable
public class UserAccountId implements Serializable {

    @Column(name = "user_id")
    private String userId;

    @Column(name = "account_id")
    private String accountId;

    private UserAccountId() {
    }

    public UserAccountId(
            String userId,
            String accountId) {
        this.userId = userId;
        this.accountId = accountId;
    }

    //Getters  Setters..
}

Сущность пользователя:

@Entity
@Table(name = "users")
public class User implements Serializable {

    @Id
    @Column(name = "id", unique = true, nullable = false)
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "org.hibernate.id.UUIDGenerator")
    private String id;

    @Column(name = "email", nullable = false)
    private String email;

    @Column(name = "full_name", nullable = false)
    private String fullName;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<UserAccount> accounts;

    public User() {
        accounts = Sets.newHashSet();
    }



    public void addAccont(Account account) {
        UserAccount userAccount = new UserAccount(this, account);
        accounts.add(userAccount);
        account.getUsers().add(userAccount);
        this.accounts.add(userAccount);
    }

    public void removeAccont(Account account) {
        for (Iterator<UserAccount> iterator = accounts.iterator(); iterator.hasNext(); ) {
            UserAccount userAccount = iterator.next();

            if (userAccount.getUser().equals(this) &&
                    userAccount.getAccount().equals(account)) {
                iterator.remove();
                userAccount.getAccount().getUsers().remove(userAccount);
                userAccount.setUser(null);
                userAccount.setAccount(null);
            }
        }
    }

    //Getters  Setters..

}

Сущность счета:

@Entity
@Table(name = "accounts")
public class Account implements Serializable {

    @Id
    @Column(name = "id", unique = true, nullable = false)
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "org.hibernate.id.UUIDGenerator")
    private String id;

    @Column(name = "name", nullable = false)
    private String name;

    @Column(name = "billing_address", nullable = false)
    private String billingAddress;

    @OneToMany(mappedBy = "account", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<UserAccount> users;


    public Account() {
        users = Sets.newHashSet();
    }

    //Getters  Setters..
}

Я могу легко добавить дополнительный столбец вкласс UserAccount, но мне нужно добавить набор ролей для каждого UserAccount, также можно назначить роль нескольким объектам UserAccount, чтобы пользователь мог иметь другой набор ролейдля каждого из своих аккаунтов.Это правильно / имеет смысл?следует добавить в класс UserAccount отношение @ManyToMany к Role:

@Entity
@Table(name = "users_accounts")
public class UserAccount implements Serializable {

    @EmbeddedId
    private UserAccountId id;

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("userId")
    private User user;

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("accountId")
    private Account account;

    @ManyToMany(
        fetch = FetchType.LAZY,
        cascade = {
                CascadeType.PERSIST,
                CascadeType.MERGE
        })
    @JoinTable(
        name = "users_accounts_roles",
        joinColumns = {
                @JoinColumn(name = "user_id", referencedColumnName = "user_id"),
                @JoinColumn(name = "account_id", referencedColumnName = "account_id"),
        },
        inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id")
)
private Set<Role> roles;


    private UserAccount() {}

    public UserAccount(@NotNull User user, @NotNull Account account) {
        this.user = user;
        this.account = account;
        roles = Sets.newHashSet();
        this.id = new UserAccountId(user.getId(), account.getId());
    }

    //Getters  Setters..

}

1 Ответ

1 голос
/ 20 сентября 2019

Это правильно / имеет смысл?

Ваше решение будет работать, просто оно звучит как очень сложная модель.Вы уверены, что связь «многие ко многим» не должна находиться между Role и Account (а не UserAccount)?Другими словами, будет Account иметь разные Roles в зависимости от того, какой User использует его?

Кроме того, я обнаружил проблему в вашем предложенном отображении.Возможно, вы захотите:

@JoinTable(
            name = "users_accounts_roles",
            joinColumns = {
                @JoinColumn(name = "user_id", referencedColumnName = "user_id"),
                @JoinColumn(name = "account_id", referencedColumnName = "account_id"),
            },
            inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id")
    )

(поскольку в UserAccount нет столбца id для ссылки; скорее, есть два столбца первичного ключа)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...