当前位置: 首页 > 知识库问答 >
问题:

具有额外多个关系的JPA多个

邹浩
2023-03-14

我需要支持一个涉及以下实体的场景(使用JPA):

  1. 用户

一个用户可以有多个帐户,一个帐户可以在多个用户之间共享,这是迄今为止的标准@ManyToMany关系。

一个用户可以为每个帐户拥有一组不同的角色,一个角色可以在多个用户之间共享。

我遵循了这个实践,它解释了一种用额外列映射多对多关联的方法,但我不确定我是否得到了它。

用户实体:

@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> usersAccounts;

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

    public User(String email, String fullName) {
        this();
        this.email = email;
        this.fullName = fullName;
    }



    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> usersAccounts;


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

    //Getters  Setters..
}

用户帐户实体:

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

    @EmbeddedId
    private UserAccountId id;

    @ManyToOne(
        fetch = FetchType.LAZY,
        cascade = {
                CascadeType.PERSIST,
                CascadeType.MERGE
        })
    private User user;

    @ManyToOne(
        fetch = FetchType.LAZY,
        cascade = {
                CascadeType.PERSIST,
                CascadeType.MERGE
        })
    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..

}

用户帐号:

@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..
}

我正在创建一个新用户并尝试将其保存到DB:

User user = new User("some.email@mail.com", "John Doe");
userRepository.save(savedEntity);

我得到了JpaSystemException:

Caused by: java.sql.SQLException: Field 'user_account_account_id' doesn't have a default value

查看hibernate的create table语句,我看到:

create table users
(
  id                      varchar(255) not null
    primary key,
  email                   varchar(255) not null,
  full_name               varchar(255) not null,
  user_account_account_id varchar(255) not null,
  user_account_user_id    varchar(255) not null,
  constraint UK_exxyrhm7e34pwn8dvem8wxuxu
  unique (user_account_account_id, user_account_user_id),
  constraint FKhti2663qxk7qo15f7gfnnaj7r
  foreign key (user_account_account_id, user_account_user_id) references users_accounts (account_id, user_id)
)
  engine = InnoDB;

我不清楚标记为非空的user\u account\u account\u iduser\u account\u user\u id列,据我的实体所知,在这些列中可以创建没有帐户的用户。

为什么以这种方式创建表?我如何使它工作?


共有2个答案

诸葛雅达
2023-03-14

我的感觉是,user_account_account_iduser_account_user_id列都是您之前尝试的剩余部分。您可以安全地删除它们,一切都会正常进行。

为了安全起见,您可以完全删除users表,然后从头开始重新创建它。

施茂
2023-03-14

这是否正确/合理?

您的解决方案会起作用,只是它听起来是一个非常复杂的模型。您确定多对多关联不应该在角色帐户之间(而不是用户帐户)吗?换句话说,帐户是否会有不同的角色取决于哪个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")
    )

(因为在用户帐户中没有可引用的id列;相反,有两个主键列)

 类似资料:
  • 问题内容: 有三个表:,并且,医院能提供的医疗服务和语言服务。因此,存在两个多对多关系。 简单ERD 现在,我想使用和搜索医院数据。 DaoImpl: 而且,如果我想从三个表中按邮政编码,医疗类型和语言进行搜索,那么如何编写一个jsql。 警告: 错误:org.hibernate.hql.internal.ast.ErrorCounter- 预期加入的路径!希望加入的路径!在org.hiberna

  • 我继承了一个项目,它有一些CRUD形式...在创建表单中,我们需要创建一个和关系的条目。所以基本上我得到的是以下这些 我不确定这是否是最好的方法,但似乎有效。 我遇到的问题是,在表单中,这些参与者/评论可以编辑、添加或删除,我不确定如何更新它们。是否可以更新它们,或者删除现有关系数据并重新添加它们是否更好? 我从来没有更新过关系,只是添加了它们,所以我不确定如何开始。 任何帮助都将不胜感激。

  • 问题内容: Book,User和Review说,我正在构建具有复杂模型的应用程序。 评论包含书籍和用户ID。为了能够搜索至少包含一个评论的“图书”,我已将“图书”设置为“评论”的父级,并且具有这样的路由。但是,我还需要找到撰写包含某些短语的评论的用户。 是否可以同时将书和用户作为评论的父级?有没有更好的方法来处理这种情况? 请注意,我无法更改数据建模的方式/不愿意这样做,因为数据已从持久性数据库传

  • 我是新来laravel的,所以原谅我可能的愚蠢问题。此外,我确实研究了所有其他“类似”的问题,但要么它们没有重现正确的解决方案,要么我真的很难理解。 情景: 我有一个帖子模型和一个主题模型。这就是他们现在的样子。 在岗位上。php 在主题上。php 现在,我需要实现的是: 如果将查询参数传递给请求(即q=Food),我只想返回在主题关系中包含主题食物的帖子,而不返回其他帖子。如果什么都没有通过,那

  • 我有一出戏!使用ebean进行模型管理的框架项目。我有4个模型,A B C D. A和B是oneTo多,B和C是OneTo多,B和D是One To多。现在我想要一个与所有相关的B C D链接的A列表。 我现在拥有的是 但是性能非常差,根据sql日志,sql查询没有按照我的要求进行连接。是否有任何方法可以对所有这些对象使用查询联接?(即,选择包含4个查询的所有A B C D,并在本地连接它们,而不是

  • 如何为这种多对多关系分配默认值?制作两个关联表->一个用于收件箱-关系,另一个用于发件箱-关系会更好吗?我该如何做到这一点?这个问题的其他解决方案? 任何帮助都非常感谢--非常感谢!