Содержание

Шпаргалка по Hibernate

Чтобы не гуглить по всему интернету :D

Backend Java Developer
Backend Java Developer

Oбновлена 2021-04-20: Добавил про дублирование записей при @OneToMany и @ElementCollection

Решил собрать небольшую шпаргалку, с полезными трюками по Hibernate. Чтобы не приходилось их каждый раз судорожно гуглить.

Статья будет обновляться по мере необходимости.

У нас есть сущность Project и другая сущность Task. В каждом проекте может быть много задач.

Вы можете разработать схему базы данных для этого сценария двумя способами.

Первое решение - создать таблицу с именем Project и другую таблицу с именем Task и добавить столбец внешнего ключа в таблицу задач с именем project_id:

Project      Task
views: 94
-------      ----
id           id
name         name
             project_id

Другое решение - использовать третью таблицу. В нашем случае Project_Task и сохранить отношения между проектами и задачами в этой таблице.

Project      Task      Project_Task
views: 94
-------      ----      -------------
id           id        project_id
name         name      tasks_id

Таблица Project_Task называется Таблица соединения. Используйте аннотацию @JoinTable, чтобы реализовать это в JPA.

Если вы хотите создать схему для ассоциации «многие ко многим», использование таблицы соединений - единственное доступное решение.

Чтобы реализовать однонаправленную ассоциацию «один ко многим», мы создадим сущности

Сущность Project:

@Entity
public class Project {

    @Id
    @GeneratedValue
    private Long pid;

    private String name;

    @JoinTable
    @OneToMany
    private List<Task> tasks;

    // ... ... ... ... ...

}

Сущность Task:

@Entity
public class Task {

    @Id
    @GeneratedValue
    private Long tid;

    private String name;

    // ... ... ... ... ...

}

Это подходит для следующей структуры БД:

Схема

Обратите внимание на названия. Соединяющая таблица называется, как “Главная таблица + Зависящая”. Также название поля должно быть с окончанием s: не task_id, а tasks_id. Это позволит использовать @JoinTable без указания параметров.

Аннотация @JoinTable также позволяет настраивать различные аспекты объединенной таблицы. Это нужно, когда имена и поля связующей таблицы названы не по конвеншену.

Для такой схемы необходимо указать параметры @JoinTable.

Вторая схема

@JoinTable(
        name = "MY_JT",
        joinColumns = @JoinColumn(
                name = "PROJ_ID",
                referencedColumnName = "PID"
        ),
        inverseJoinColumns = @JoinColumn(
                name = "TASK_ID",
                referencedColumnName = "TID"
        )
)
@OneToMany
private List<Task> tasks;

Если вы используете @ManyToOne, то для аннотации для @JoinTable обязательно указываются параметры.

По умолчанию enum сохраняется в базу в виде порядкового числа элемента в енуме. Я предпочитаю сохранять именно значение элемента, для наглядности.

Для этого используется аннотация @Enumerated(EnumType.STRING)


@Entity
@Table(name = "app_setting")
public class AppSetting {

    // ... ... ... ... ...

    @Enumerated(EnumType.STRING)
    private AppLocale appLocale;

    // ... ... ... ... ...

}

Порой для сущности необходимо сохранить обычный набор значений, например Set<String> или List<Long>.

Допустим у нас есть книги, а у книг может быть множество жанров(lable). В базе данных это выглядит так.

Схема коллекции обычных элементов

Чтобы не создавать отдельную сущность, можно сразу использовать Set.


@Entity
@Table(name = "book")
public class Book {

    // ... ... ... ... ...

    @ElementCollection
    @CollectionTable(name = "book_label", joinColumns = @JoinColumn(name = "book_id"))
    @Column(name = "label")
    private Set labels = new HashSet<>();

    // ... ... ... ... ...

}

При совместном использовании @ElementCollection и @OneToMany, могут образоваться дубликаты в @OneToMany. О том, как это исправить, я написал в отдельной статье.

Комментарии