JavaRush /Курсы /Модуль 4. Работа с БД /Работа с иерархиями сущностей

Работа с иерархиями сущностей

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

Проблемы сохранения

Сегодня у нас будет новая и суперинтересная схема — использование возможностей Hibernate для сохранения в базу иерархии классов.

Иерархия классов — это несколько классов, связанных друг с другом отношением наследования.

Представь, что у тебя есть три класса, которые ты хочешь хранить в базе:


class User {
  int id;
  String name;
  LocalDate birthday;
}

class Employee extends User {
 	String occupation;
 	int salary;
 	LocalDate join;
}

class Client extends User {
   String address;
}

Классы унаследованы друг от друга. А самое интересное в том, что ты хочешь использовать Hibernate для того, чтобы хранить объекты этих классов в базе данных.

Виды решений

В Hibernate существует 4 возможных способа, которыми он может связать иерархию классов с таблицами в базе данных:

  • MappedSuperclass
  • Single Table
  • Joined Table
  • Table per class

Каждая стратегия предполагает свою собственную структуру таблиц в базе данных. Иногда они довольно сложные. Зато запросы на HQL к ним очень простые. Это как раз тот случай, где ярко проявляются преимущества Hibernate.

Никогда не слышал, чтобы эти термины переводили на русский, так что тоже рекомендую произносить их на английском.

Ниже мы разберем, что означает каждый их них.

@MappedSuperClass

Начнем с самого простого решения — в базе данных у тебя отдельные таблицы для каждого класса. Например, такие:


CREATE TABLE user {
  id INT,
  name VARCHAR,
  birthday DATE
}

CREATE TABLE employee {
  id INT,
  name VARCHAR,
  birthday DATE,
  occupation VARCHAR,
  salary INT,
  join DATE
}

CREATE TABLE client {
  id INT,
  name VARCHAR,
  birthday DATE,
  address VARCHAR
}

О том, что классы для этих таблиц связаны в иерархию, знаешь только ты. Если ты хочешь, чтобы еще и Hibernate об этом знал, тебе нужно добавить родительскому классу аннотацию @MappedSuperclass. Без нее Hibernate просто проигнорирует поля и аннотации родительского класса.

Классы с этой аннотацией будут выглядеть так:


@MappedSuperclass
class User {
  int id;
  String name;
  LocalDate birthday;
}

@Entity
class Employee extends User {
 	String occupation;
 	int salary;
 	LocalDate join;
}

@Entity
class Client extends User {
   String address;
}

Это самый примитивный способ связывания иерархии классов и базы данных. Такой подход фактически позволяет тебе только избежать дубликата полей в классах.

Запросы к базе данных на HQL будут возвращать только ту сущность, тип которой указан явно. Ты не можешь написать запрос к базе на HQL и получить список всех пользователей: User, Employee, Client.

1
Задача
Модуль 4. Работа с БД, 15 уровень, 0 лекция
Недоступна
Стратегия MappedSuperClass
Посмотри на скрипт по созданию таблиц. Создай классы-сущности для этих таблиц. Обрати внимание на поля, которые повторяются. Для избежания дублирования используй наследование. Расставь правильно аннотации созданным классам. Не забудь про поле Long id в каждом классе-сущности.
Комментарии (11)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Егор Степанов Уровень 111
8 апреля 2025
В условие задачи пишется: "Для избежания дублирования используй наследование. Расставь правильно аннотации созданным классам. Не забудь про поле Long id в каждом классе-сущности." На деле же валидатор принимает только через Integer. Кстати Id указал только для класса Person.
Олег Уровень 109 Expert
1 августа 2024
про Long id тоже не понял, валик принял Integer
Руслан Уровень 115
26 июля 2024
В задаче над классом Person дополнительно поставили аннотацию @Table, но её не надо ставить т.к. класс обозначенный @MappedSuperClass нельзя добавить в таблицу
Ольга Николенко Уровень 109 Expert
11 июня 2024
Не верьте условиям в задаче) нужен Integer id и не во всех классах. (валидатор требует)
Дмитрий Уровень 111 Expert
31 января 2024
Не получается сохранить объект класса User, класс не мапится на таблицу. Его можно сохранить вообще, или это не предусмотрено? Такое ощущение, что в примерах многое опущено.
SchlechtGut Уровень 51
19 августа 2023
полиморфный запрос доступен. При этом нужно указать полное название класса (вместе с пакетом)
Александр Уровень 111 Expert
6 февраля 2023
Прописал айдишке Long, как просят в условии, не приняло. Написал Integer и прошел валидацию. Зачем вводить в заблуждение этой фразой "Не забудь про поле Long id в каждом классе-сущности"?
Алексей Уровень 16
2 апреля 2025
Странно что спустя год так и не исправили :(
Алексей Уровень 91 Expert
7 декабря 2022
В задачке нужно не просто классы создать, но и все аннотации включая поля и геттеры с сеттерами, хотя в задании в требованиях это не указано
Nikita Shamrai Уровень 8 Expert
10 декабря 2022
Геттеры и сеттеры должны быть по стандарту в любом Энтити классе
Justinian Уровень 41 Master
9 февраля 2023
это учебная задача, поэтому да, надо писать геттеры и сеттеры не ошибешься. Но если говорить за реальные классы, то нужно взвешивать, что требуется и почему, вот мысли на тему можно почитать https://thorben-janssen.com/access-strategies-in-jpa-and-hibernate/ Главное чтобы стандарты были для нас и решали некие проблемы, а не мы для стандартов. Хотя безусловно, по стадиям обучения, сначала мы просто повторяем, а потом разбираем зачем это и какие исключения