1. Проблеми збереження

Сьогодні в нас буде нова та суперцікава схема — використання можливостей 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 для того, щоб зберігати об'єкти цих класів у базі даних.

2. Види рішень

У Hibernate існує 4 можливі способи, якими він може пов'язати ієрархію класів з таблицями в базі даних:

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

Кожна стратегія передбачає власну структуру таблиць у базі даних. Іноді вони досить складні. Проте запити на HQL до них дуже прості. Це саме той випадок, де яскраво виявляються переваги Hibernate.

Ніколи не чув, щоб ці терміни перекладали з англійської, тож рекомендую вимовляти їх в оригіналі.

Нижче ми розберемо, що означає кожен з них.

3. @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.