使用JPA /休眠将不同表的主键数据作为外键自动填充到另一个表中

问题描述 投票:0回答:2

下面是预期的表结构:

Users -> user_id (PK)
RoleA -> role_a_id (PK)
RoleB -> role_b_id (PK)
User_Roles -> user_id (FK), role_a_id (FK), role_a_id (FK)

下面是实体类:

@Table(name = "users")
@Entity
public class Users {

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "user_id")
    private int userId;

    @OneToMany(cascade = CascadeType.ALL)
    @JoinTable(
      name = "user_roles", 
      joinColumns = @JoinColumn(name = "user_id"), 
      inverseJoinColumns = @JoinColumn(name = "role_a_id"))
    Set<RoleA> rolesA;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinTable(
      name = "user_roles", 
      joinColumns = @JoinColumn(name = "user_id"), 
      inverseJoinColumns = @JoinColumn(name = "role_b_id"))
    RoleB rolesB;

    public Set<RoleA> getRolesA() {
        return rolesA;
    }

    public void setRolesA(Set<RoleA> rolesA) {
        this.rolesA = rolesA;
    }

    public RoleB getRolesB() {
        return rolesB;
    }

    public void setRolesB(RoleB rolesB) {
        this.rolesB = rolesB;
    }
}
@Table(name = "role_a")
@Entity
public class RoleA {

    public int getRoleAId() {
        return roleAId;
    }

    public void setRoleAId(int roleAId) {
        this.roleAId = roleAId;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "role_a_id")
    private int roleAId;
}
@Table(name = "role_b")
@Entity
public class RoleB {

    public int getRoleBId() {
        return roleBId;
    }

    public void setRoleBId(int roleBId) {
        this.roleBId = roleBId;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "role_b_id")
    private int roleBId;
}

插入数据的代码:

RoleA roleA = new RoleA();
roleA.setRoleAId(1);
Set<RoleA> rolesA = new HashSet<>();
rolesA.add(roleA);

RoleB roleB = new RoleB();
roleB.setRoleBId(2);

Users user = new Users();
user.setUserId(10);
user.setRolesA(rolesA);
user.setRolesB(roleB);

userDAO.addUser(user);

启动服务器时,所有表均按预期方式创建,但是一旦尝试按上述方法插入数据,则出现以下错误:

2020-04-01 17:14:35.203 DEBUG 30244 --- [p-nio-80-exec-2] org.hibernate.SQL                        : insert into users (user_id) values (?)
2020-04-01 17:14:35.206 TRACE 30244 --- [p-nio-80-exec-2] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [INTEGER] - [95]
2020-04-01 17:14:35.249 DEBUG 30244 --- [p-nio-80-exec-2] org.hibernate.SQL                        : insert into user_roles (role_b_id, user_id) values (?, ?)
2020-04-01 17:14:35.250 TRACE 30244 --- [p-nio-80-exec-2] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [INTEGER] - [2]
2020-04-01 17:14:35.251 TRACE 30244 --- [p-nio-80-exec-2] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [INTEGER] - [95]
2020-04-01 17:14:35.310  WARN 30244 --- [p-nio-80-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 0, SQLState: 23502
2020-04-01 17:14:35.311 ERROR 30244 --- [p-nio-80-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper   : ERROR: null value in column "role_a_id" violates not-null constraint
  Detail: Failing row contains (2, 95, null).
2020-04-01 17:14:35.393 DEBUG 30244 --- [p-nio-80-exec-2] c.h.refoearn.controller.UserController   : DataIntegrityViolationException while adding user: could not execute statement; SQL [n/a]; constraint [role_a_id]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement

根据User_Roles的日志插入语句,未考虑将role_a_id插入并声明为非null,则抛出异常。

Can someone please suggest the root cause why role_a_id is not being taken care while insertion in User_Roles ?
What is the missing piece stopping it to happen ?
Any other suggestion to fulfill the requirement if shared approach is not correct ?
hibernate jpa join jpa-2.0 multiple-join-rows
2个回答
0
投票

似乎在意图和执行方面可能存在一些差距。 User_Roles表的确切目的尚不清楚。该表保持着什么关系?是否试图将Users表与

相关联
  1. RoleA
  2. RoleB
  3. RoleARoleB均>
  4. 如果是第一种情况,则role_b_id不应该存在。如果是第二种情况,则role_a_id不应该存在。

对于第三种情况,您可能需要重新考虑您的设计。考虑一下您想定义什么关系,即以下任一情况都可能适用

  1. 用户与RoleARoleB都相关,但是RoleARoleB不相互依赖。
  2. 用户与RoleARoleB都相关,并且RoleARoleB相互依赖。
  3. [通过查看Users类,因为它与OneToOne具有RoleB关系,我的第一个猜测是,这是RoleARoleB彼此不依赖的第一点。考虑到您应该完全删除role_b_id表中的User_Roles列,并将其直接添加为Users表的一部分,或者为其创建其他表。


0
投票

经过分析和不同的建议,我发现如果我们将User_Roles表的两列视为主键,它们将具有冗余数据。从数据库规范化的角度来看,这将是糟糕的设计。如果这三列都是唯一的并且充当主键,那么我看不到该表的任何特定用途。

© www.soinside.com 2019 - 2024. All rights reserved.