1. Опис

Наступний підхід до зберігання ієрархії класів — це зберігати всі класи ієрархії в одній таблиці. Така стратегія називається Single Table.

Наприклад, так:


CREATE TABLE user_ employee_client {
  id INT,
  name VARCHAR,
  birthday DATE,
  occupation VARCHAR,
  salary INT,
  join DATE,
  address VARCHAR,
  DTYPE VARCHAR
}

Тобто, у нас є одна таблиця, у якої колонки для всіх класів нашої ієрархії позначені різними кольорами. Також є спеціальна службова колонка DTYPE VARCHAR, де Hibernate зберігатиме ім'я Entity-класу.

Залишилося небагато: треба пояснити Hibernate, що дані Entity-класів тепер зберігаються у базі в одній таблиці. Зробити це можна за допомогою анотації @Inheritance:


@Inheritance(strategy = InheritanceType.SINGLE_TABLE)

Приклад наших класів:


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

2. Як дані зберігаються

Тепер давай напишемо приклад, де створимо парочку наших сутностей та збережемо їх до бази:


Employee employee = New Employee();
employee.id = 101;
employee.name = "Іванов";
employee.birthday = LocalDate.of("01-01-1999");
employee.occupation = "Програміст"
employee.salary = 100000;
employee.join = LocalDate.of("12-01-2018");
session.persist(employee);
 
Client client = new Client();
client.id = 102;
client.name = "Петров";
client.birthday = LocalDate.of("15-11-1988");
client.address = "Шандара";
session.persist(client);

При збереженні до бази даних буде виконано такий SQL-запит:


INSERT INTO user_ employee_client (id, name, напередодні, occupation, salary, join, DTYPE)
VALUES (101, 'Іванів', '01-01-1999', 'Програміст', 100000, '12-01-2018', 'Employee')
 
INSERT INTO user_ employee_client (id, name, birthday, address, DTYPE)
VALUES (102, 'Петрів', '15-11-1988', 'Шандара', 'Client')

Під час збереження даних до таблиці Hibernate передає лише відомі йому поля сутностей. Це означає, що не вказані колонки матимуть значення NULL.

А це означає, що ти не можеш вказати для колонки occupation тип NOT NULL, тому що під час зберігання клієнта в цій же таблиці його occupation буде NULL. Це один із мінусів зберігання різних сутностей в одній таблиці.

Останнє поле SQL-запиту — це колонка DTYPE, у ній передається ім'я Entity-класу. Він використовується Hibernate, коли ти хочеш прочитати дані зі своєї таблиці.

Приклад:


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

Цей запит поверне список усіх збережених у базі об'єктів типу користувач: User, Employee та Client. На основі колонки DTYPE буде правильно визначено тип сутності та створено об'єкт правильного класу.

У нашому випадку в списку accounts будуть два об'єкти: типу Employee та типу Client.

HQL рулить.