@OneToMany

Модуль 4. Работа с БД
13 уровень , 2 лекция
Открыта

Связь на уровне таблиц

Давай опять рассмотрим две наши таблицы:

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).

Связь на уровень 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;
}

Аннотация @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.

Примеры запросов

Если ты хочешь добавить какому-то работнику некоторый task, то тебе нужно написать код типа такого:


EmployeeTask task1 = new EmployeeTask();
task1.description = "Сделать что-то важное";
session.persist(task1);
 
EmployeeTask task2 = new 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-классы для этих таблиц – разные.

1
Задача
Модуль 4. Работа с БД, 13 уровень, 2 лекция
Недоступна
Автор книги или книга автора?
Есть три класса-энтити: Author, Book и Publisher, и таблицы, которые им соответствуют...
Комментарии (7)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Егор Степанов Уровень 111
5 апреля 2025
Задачу не принимает, если мы явно укажем SELECT в HQL запросе. Не принимает с алиасами. Не принимает без

query.setParameter("AUTHOR_FULLNAME", "Mark Twain")
Предвкушая вопросы зачем использовал SELECT, отвечу сразу. "Задача не компилируется на сервере". Не знаю почему, но пока не написал SELECT проверка даже не начиналась. Потом убрал и все заработало.
Артём Уровень 105
17 июля 2025
А ещё на консоль надо выводить не просто названия книг, а весь класс Book.
Руслан Никитин Уровень 109
5 февраля 2025
Аннотация @OneToMany в JPA используется для обозначения связи "один ко многим" и применяется к полям, которые представляют собой коллекции дочерних сущностей - используем сет, лист или мап для поля
Дмитрий Уровень 37
17 марта 2024
зачем делать session.update(director);? Если объект и так получен при помощи метода find то есть и так находится под управлением хибера
Gans Electro Уровень 41
29 июля 2024
Разве говорили что все изменения происходят моментально?
Надежда Уровень 104 Expert
1 октября 2023
Исправьте название таблицы в аннотации: вместо @Table(name="user") надо @Table(name="employee") и добавьте аннотацию @Id для Integer id.
hint1k Уровень 51
11 июня 2023
task2 очевидно должен быть поручен employee id = 6, а не 4 😄