Автоматическое заполнение данных первичных ключей разных таблиц в другую таблицу как внешние ключи с использованием JPA / Hibernate - PullRequest
0 голосов
/ 01 апреля 2020

Ниже приведена ожидаемая структура таблицы:

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 быть вставленным и объявленным как ненулевое, исключение - throw.

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 ?

Ответы [ 2 ]

0 голосов
/ 02 апреля 2020

После анализа и различных предложений я обнаружил, что таблица User_Roles будет иметь избыточные данные, если мы рассмотрим 2 ее столбца в качестве первичного ключа. Это будет плохой дизайн с точки зрения нормализации БД. Если все три столбца уникальны и выступают в качестве первичного ключа, то я не вижу конкретного использования таблицы.

Таким образом, лучшее решение состоит в том, чтобы у roleId было однозначное сопоставление с самой таблицей пользователя и однозначное с таблицей User_Roles. Итак, окончательная структура таблицы будет выглядеть следующим образом:

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

Эту структуру можно получить, изменив таблицу пользователей следующим образом:

@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)
    @JoinColumn(name = "rolesB")
    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;
    }
}
0 голосов
/ 01 апреля 2020

Похоже, что может быть какой-то пробел в намерении и реализации. Точное назначение таблицы User_Roles не ясно. Какое отношение имеет этот стол? Пытается ли связать таблицу Users с

  1. RoleA
  2. RoleB
  3. с RoleA и RoleB

Если это 1-й случай, то role_b_id не должно существовать. Если это 2-й случай, то role_a_id не должно существовать.

В третьем случае вам может понадобиться переосмыслить свой дизайн. Подумайте, какие отношения вы хотите определить, т. Е. Может применяться любой из следующих пунктов:

  1. Пользователь связан с RoleA и RoleB, но RoleA и RoleB не зависят от друг с другом.
  2. Пользователь связан с RoleA и RoleB, а RoleA и RoleB зависят друг от друга.

Взгляд на Users класс, поскольку он имеет отношение OneToOne к RoleB, и я думаю, что это первая точка, в которой RoleA и RoleB не зависят друг от друга. Учитывая, что вы должны полностью удалить столбец role_b_id в таблице User_Roles и добавить его непосредственно как часть таблицы Users, либо создать для него другую таблицу.

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