5.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,
address VARCHAR
}
Основное отличие – это то, что используется сквозной id (PRIMARY KEY) для всех таблиц. У тебя не могут быть разные строки с одним id не только в рамках одной таблицы, но и в рамках этой группы таблиц. Hibernate будет следить за этим.
5.2 Примеры
Очень интересно разобрать, как это все работает.
Ты можешь написать простой HQL-запрос, чтобы получить всех пользователей: User, Employee, Client:
List<User> accounts = session.createQuery("from User").list();
А вот Hibernate, в свою очередь, сгенерирует очень интересный запрос. Он сделает выборку из всех таблиц, потом объединит ее через UNION ALL в подобие виртуальной таблицы, и только потом будет выполнять по ней поиск и/или выборку
Но чтобы объединить таблицы с разными колонками, сначала их нужно дополнить фейковыми колонками. Например, таблицу user нужно дополнить колонками:
occupation VARCHAR
salary INT
join DATE
address 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
, и только потом фильтровать.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ