1. Опис

І нарешті остання стратегія — це Table per class. Вона означає, що для кожного класу використовуватиметься окрема таблиця. В якомусь сенсі це той самий MappedSuperClass, тільки в оновленому вигляді.

По-перше, тобі потрібно використовувати анотацію:

@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

Класи з цією анотацією будуть виглядати так:


@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@Entity
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;
}

І окремі таблиці кожного класу. Наприклад, такі:


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,
адреса VARCHAR
}

Основна відмінність — це те, що використовується наскрізний ID (PRIMARY KEY) для всіх таблиць. У тебе не можуть бути різні рядки з одним ID не лише в межах однієї таблиці, але і в межах цієї групи таблиць. Hibernate стежитиме за цим.

2. Приклади

Дуже цікаво розібрати, як це все працює.

Ти можеш написати простий HQL-запит, щоб отримати всіх користувачів: User, Employee, Client:

List<User> accounts = session.createQuery("from User").list();

А ось Hibernate, у свою чергу, згенерує дуже цікавий запит. Він зробить вибірку з усіх таблиць, потім об'єднає її через UNION ALL на кшталт віртуальної таблиці, і лише потім виконуватиме за нею пошук та/або вибірку.

Але щоб поєднати таблиці з різними колонками, спочатку їх потрібно доповнити фейковими колонками. Наприклад, таблицю user потрібно доповнити колонками:

  • occupation VARCHAR
  • salary INT
  • join DATE
  • адреса VARCHAR

Приклад SQL-запиту до таблиці user перед виконанням UNION ALL:


SELECT id,
         name,
         birthday,
         CAST(NULL AS VARCHAR) AS occupation,
         CAST(NULL AS INT) AS salary,
         CAST(NULL AS DATE) AS join,
         CAST(NULL AS VARCHAR) AS address,
         0 AS clazz
FROM user

Приклад SQL-запиту до таблиці employee перед виконанням UNION ALL:


SELECT id,
         name,
         birthday,
         occupation,
         salary,
         join,
         CAST(NULL AS VARCHAR) AS address,
         1 AS clazz
FROM employee

Приклад SQL-запиту до таблиці client перед виконанням UNION ALL:


SELECT id,
        name,
        birthday,
        CAST(NULL AS VARCHAR) AS occupation,
        CAST(NULL AS INT) AS salary,
        CAST(NULL AS DATE) AS join,
        address,
        2 AS clazz
FROM client

Хороша новина: HQL-запити працюватимуть так, як тобі хотілося б.

Погана новина: вони можуть працювати повільно, якщо даних у таблицях дуже багато. Тому що спочатку дані потрібно вибрати зі всіх таблиць, потім об'єднати їх рядки за допомогою UNION ALL, і лише потім фільтрувати.