1. Зв'язок на рівні таблиць

Давай знову розглянемо дві наші таблиці:

id name occupation salary age join_date
1 Шевченко Ігор Програміст 100000 25 2012-06-30
2 Коваленко Максим Програміст 80000 23 2013-08-12
3 Шевченко Данило Тестувальник 40000 30 2014-01-01
4 Мельник Степан Директор 200000 35 2015-05-12
5 Кірієнко Анастасія Офіс-менеджер 40000 25 2015-10-10
6 Пончик Кіт 1000 3 2018-11-11

Таблиця employee:

У цій таблиці є такі колонки:

  • id INT
  • name VARCHAR
  • occupation VARCHA
  • salary INT
  • age INT
  • join_date DATE

А так виглядає таблиця task, яка містить завдання для співробітників:

id emploee_id name deadline
1 1 Виправити багу на фронтенді 2022-06-01
2 2 Виправити багу на бекенді 2022-06-15
3 5 Купити каву 2022-07-01
4 5 Купити каву 2022-08-01
5 5 Купити каву 2022-09-01
6 (NULL) Прибрати офіс (NULL)
7 4 Насолоджуватися життям (NULL)
8 6 Насолоджуватися життям (NULL)

У цій таблиці є лише 4 колонки:

  • id — унікальний номер завдання (та рядки у таблиці).
  • employee_id — ID співробітника з таблиці employee, на якого призначено завдання.
  • name — назва та опис завдання.
  • deadline — час, до якого потрібно виконати завдання.

На один запис таблиці employee можуть посилатися багато рядків таблиці task. Такий зв'язок на рівні таблиць називається один-до-багатьох (one-to-many).

2. Зв'язок на рівень Java-класів

І наші класи, клас Employee:


@Entity
@Table(name="user")
class Employee {
   @Column(name="id")
   public Integer id;
 
   @Column(name="name")
   public String name;
 
   @Column(name="occupation")
   public String occupation;
 
   @Column(name="salary")
   public Integer salary;
 
   @Column(name="join_date")
   public Date join;
}

І клас EmployeeTask у його первісному вигляді:


@Entity
@Table(name="task")
class EmployeeTask {
   @Column(name="id")
   public Integer id;
 
   @Column(name="name")
   public String description;
 
   @Column(name="employee_id")
   public Integer employeeId;
 
   @Column(name="deadline")
   public Date deadline;
}

3. Аннотація @OneToMany

Ми можемо організувати зв'язок Entity-класів по-іншому.

Пам'ятаєш анотацію @ElementCollection, за допомогою якої ми в батьківському класі створювали колекцію дочірніх об'єктів? Щось схоже можна зробити за допомогою анотації @OneToMany. Лише цього разу зміни зазнають клас Employee:


@Entity
@Table(name="user")
class Employee {
   @Column(name="id")
   public Integer id;
 
   @OneToMany(cascade = CascadeType.ALL)
   @JoinColumn(name = "employee_id")
   private Set<EmployeeTask> tasks = new HashSet<EmployeeTask>();
}

За допомогою анотації @OneToMany ми вказали, що об'єкт Employee може зберігати багато об'єктів EmployeeTask. Також за допомогою анотації @JoinColumn ми вказали, в якій колонці таблиці task зберігається id об'єкта Employee.

Водночас клас EmployeeTask зазвичай не містить поля, яке посилається на колонку employee_id. Приклад:


@Entity
@Table(name="task")
class EmployeeTask {
   @Column(name="id")
   public Integer id;
 
   @Column(name="name")
   public String description;
 
   @Column(name="deadline")
   public Date deadline;
}

Поле employee_id вважається службовим, і його значенням управляє Hibernate.

4. Приклади запитів

Якщо ти хочеш додати якомусь працівникові певний task, то тобі потрібно написати код типу:


EmployeeTask task1 = новий EmployeeTask();
task1.description = "Зробити щось важливе";
session.persist(task1);
 
EmployeeTask task2 = новий EmployeeTask();
task2.description = "Нічого не робити";
session.persist(task2);
session.flush();
 
Employee director = session.find(Employee.class, 4);
director.tasks.add(task1);
director.tasks.add(task2);
 
session.update(director);
session.flush();

Спочатку ми створюємо два об'єкти EmployeeTask, зберігаємо їх до бази та викликаємо метод flush(), щоб виконалася операція INSERT і в об'єктів з'явилися ID.

Потім знаходимо в базі директора, беремо в нього поле tasks і додаємо йому два завдання. Потім зберігаємо директора до бази. Після цього в базі нових task в колонці employee_id з'явиться значення 4 — id директора в таблиці employee.

Важливо! Таблиці в базі однакові для анотацій @ManyToOne та @OneToMany. А ось Java-класи для цих таблиць — різні.