Spring Boot JPA @JoinTable 与现有映射表忽略 @GeneratedValue

Posted

技术标签:

【中文标题】Spring Boot JPA @JoinTable 与现有映射表忽略 @GeneratedValue【英文标题】:Spring Boot JPA @JoinTable with existing mapping table ignoring @GeneratedValue 【发布时间】:2017-09-30 16:50:39 【问题描述】:

我正在尝试在 UserUserRole 两个实体之间创建 ManyToMany 关系。

我需要在映射表UserToRoleMapping 中添加一些额外的列,因此我创建了一个用于映射表的实体,其中包含额外的列(如createdDateisActive)。

现在的问题是 JPA 忽略映射表 userRoleMappingId 列上的 @Id@GeneratedValue 注释,并使用 userId, roleId 创建复合主键。没关系。由于userRoleMappingId 列不是主键,我不再需要它,但是一旦我删除它,JPA 就会抱怨它需要一个带有@Id 注释的列。

即使我保持原样,当使用spring data repository for User保存带有某些角色的User时,它会抛出userRoleMappingId列不能为空的异常,因为存储库不会尝试为映射表生成ID,它被设置为not null

理想情况下,我希望在带有序列生成器的映射表中拥有一个主键。

创建带有额外列的 JoinTable 的正确方法是 实体?

这是一个包含示例代码的 github 存储库,用于重现问题。

https://github.com/ConsciousObserver/SpringBootJoinTableIssue.git

以下是实体代码

@Entity
@SequenceGenerator(name="USER_SEQ")
class User 
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="USER_SEQ")
    private long userId;

    @ManyToMany(fetch=FetchType.EAGER)
    @JoinTable(name="UserRoleMapping", joinColumns=@JoinColumn(name="userId"), inverseJoinColumns=@JoinColumn(name="roleId"))
    private Set<Role> roles;

    /*getters and setters */


@Entity
@SequenceGenerator(name="ROLE_SEQ")
class Role 
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="ROLE_SEQ")
    private long roleId;

    /*getters and setters */


@Entity
@SequenceGenerator(name="USER_ROLE_SEQ")
class UserRoleMapping 
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="USER_ROLE_SEQ")
    private long userRoleMappingId;

    @OneToOne
    @JoinColumn(name="userId")
    private User user;

    @OneToOne
    @JoinColumn(name="roleId")
    private Role role;

    private Date createdDate;

    /*getters and setters */

【问题讨论】:

【参考方案1】:

实体声明未反映帖子中提到的所需关系。它们应该声明如下:

用户实体

@Entity
public class User 
  @Id
  private long id;

  @OneToMany(mappedBy = "user")
  private List<UserRole> roles;

用户角色实体

@Entity
public class UserRole 
  @Id
  private long id;

  @ManyToOne
  @JoinColumn(name="userId")
  private User user;

  @ManyToOne
  @JoinColumn(name="roleId")
  private Role role;

这将确保每个User 可以有多个Roles,同样每个Role 可以分配给多个Users,这样如果Users 和Roles 都可以一起查看,就会看到多对多的映射。

【讨论】:

我需要UserRole之间的@ManyToMany关系,因此需要@JoinTable。请再次检查问题。 @11thdimension,你会得到一个@ManyToMany与我的答案的关系(每个用户可以有角色,每个角色可以分配给许多用户)。仔细阅读答案并尝试一下。使用映射表,@ManyToMany 根本不起作用,这似乎让您感到困惑。 在您的实体中(userId,roleId)之间的映射将存储在哪里? 好的,我没有看到你使用UserRole 作为映射表,我的用户表中是否必须有映射表的名称?我不能直接获取角色列表吗? 如果你使用Java 8,在User类的getRoles方法中应该可以直接编码为return roles.stream().map(UserRole::getRole).collect(Collectors::toList);。如果你不使用Java 8,方法会稍微更长,但可以轻松应用相同的翻译。

以上是关于Spring Boot JPA @JoinTable 与现有映射表忽略 @GeneratedValue的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot(十五):spring boot+jpa+thymeleaf增删改查示例

[Spring Boot] Adding JPA and Spring Data JPA

spring-data-jpa 和 spring-boot-starter-data-jpa 的区别

spring boot jpa

Spring Boot 整合Spring Data JPA

Spring Boot中使用Spring Data JPA示例