Составной РК с зависимостью FK (OneToOne)

Рейтинг: 0Ответов: 1Опубликовано: 31.01.2023

Мне досталась радость работать с таблицами

CREATE TABLE public."EMPLOYEES" (
    "EMP_ID" int8 NOT NULL DEFAULT nextval('"EMPLOYEES_EMP_ID_SEQ"'::regclass),
    "EMP_LASTNAME" varchar(32) NOT NULL,
    "EMP_NAME" varchar(32) NOT NULL,
    "EMP_MIDDLENAME" varchar(32) NOT NULL,
    "EMP_VERSION" timestamp NOT NULL DEFAULT now(),
    CONSTRAINT "EMPLOYEES_pkey" PRIMARY KEY ("EMP_ID")
);
CREATE TABLE public."EMPLOYMENTITEMS" (
    "EIS_EMPLOYEE" int8 NOT NULL,
    "EIS_POST" varchar(128) NOT NULL,
    "EIS_DATE" date NOT NULL DEFAULT now(),
    "EIS_DEPARTMENT" int8 NOT NULL,
    CONSTRAINT "EMPLOYMENTITEMS_pkey" PRIMARY KEY ("EIS_EMPLOYEE","EIS_DATE"),
    CONSTRAINT "EMPLOYMENTITEMS_EIS_DEPARTMENTS_fkey" FOREIGN KEY ("EIS_DEPARTMENT") REFERENCES public."DEPARTMENTS"("DEP_ID") ON DELETE CASCADE ON UPDATE CASCADE,
    CONSTRAINT "EMPLOYMENTITEMS_EIS_EMPLOYEE_fkey" FOREIGN KEY ("EIS_EMPLOYEE") REFERENCES public."EMPLOYEES"("EMP_ID") ON DELETE CASCADE ON UPDATE CASCADE
);

Я создал классы:

@Getter @Setter
@NoArgsConstructor
@EqualsAndHashCode(of = {"firstName", "middleName", "lastName", "details"})
@ToString(of = {"firstName", "middleName", "lastName", "details"})
@Entity
@Table(name = "\"EMPLOYEES\"")
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "\"EMP_ID\"")
    private long id;
    @Column(name = "\"EMP_NAME\"")
    private String firstName;
    @Column(name = "\"EMP_MIDDLENAME\"")
    private String middleName;
    @Column(name = "\"EMP_LASTNAME\"")
    private String lastName;
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "\"EMP_ID\"")
    private Details details;
}
@Getter @Setter
@NoArgsConstructor
@EqualsAndHashCode(of = {"post", "department"})
@ToString(of = {"post", "department"})
@Entity
@Table(name = "\"EMPLOYMENTITEMS\"")
public class Details {
    @Id
    @Column(name = "\"EIS_EMPLOYEE\"")
    private long id;
    @Column(name = "\"EIS_POST\"")
    private String post;
    @OneToOne()
    @JoinColumn(name = "\"EIS_DEPARTMENT\"")
    private Department department;
}

При выгрузке данных — всё работает, но при попытке записать новые данные, естественно выскакивает ошибка, так как оно пытается сгенерировать значение для поля, которое ограничено FK.

Код сохранения. Медов в классе Employee

public void save() {
    EntityManager em = emf.createEntityManager();
    try {
        em.getTransaction().begin();
        if (this.id == 0) {
            em.persist(this);
        }
        em.getTransaction().commit();
    } catch (Exception e) {
        em.getTransaction().rollback();
    } finally {
        em.close();
    }
}

Сгенерированный hibernate скрипт

Hibernate: 
    select
        null,
        d1_0."DEP_NAME" 
    from
        "DEPARTMENTS" d1_0 
    where
        d1_0."DEP_ID"=?
Hibernate: 
    insert 
    into
        "EMPLOYMENTITEMS"
        ("EIS_DEPARTMENT", "EIS_POST", "EIS_EMPLOYEE") 
    values
        (?, ?, ?)

Стек трейс

янв. 31, 2023 7:37:42 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 0, SQLState: 23503
янв. 31, 2023 7:37:42 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: ERROR: insert or update on table "EMPLOYMENTITEMS" violates foreign key constraint "EMPLOYMENTITEMS_EIS_EMPLOYEE_fkey"
  Подробности: Key (EIS_EMPLOYEE)=(0) is not present in table "EMPLOYEES".

Я не использую Spring JPA. Это JavaFX приложение, где я сам получаю EntityManager и работаю с объектами.

Помогите, пожалуйста, это всё правильно настроить. Может это не лучшие вводные для знакомства с hibernate, но это будет приложение, которое нужно именно мне для администрирования другой программы. Может я и мог бы это всё переписать на JDBC и ResultSet, но хотелось именно что воспользоваться фреймворком.

Ответы

▲ 1Принят

Как оказалось, есть способ просто встроить поля в объект привязывая их к столбцам других таблиц...

@Entity
@Table(name = "\"EMPLOYEES\"")
@SecondaryTable(
        name = "\"EMPLOYMENTITEMS\"",
        pkJoinColumns = @PrimaryKeyJoinColumn(
                name = "\"EIS_EMPLOYEE\"",
                referencedColumnName = "\"EMP_ID\""))
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "\"EMP_ID\"")
    private long id;
    @Column(name = "\"EMP_NAME\"")
    private String firstName;
    @Column(name = "\"EMP_MIDDLENAME\"")
    private String middleName;
    @Column(name = "\"EMP_LASTNAME\"")
    private String lastName;
    @Column(name = "\"EIS_POST\"", table = "\"EMPLOYMENTITEMS\"")
    private String post;
    @OneToOne()
    @JoinColumn(name = "\"EIS_DEPARTMENT\"", table = "\"EMPLOYMENTITEMS\"")
    private Department department;
}