1. Опис

Кожна з перерахованих вище стратегій та прийомів має свої переваги та недоліки. Загальні рекомендації щодо вибору конкретної стратегії виглядатимуть так:

Стратегія TABLE_PER_CLASS на основі UNION

Цю стратегію краще обирати, якщо поліморфні запити та асоціації не потрібні. Якщо ти рідко виконуєш (або взагалі не виконуєш) “select user from User user”. Якщо у тебе немає Entity-класів, які посилаються на User, цей варіант буде найкращим (оскільки можливість додавання оптимізованих поліморфних запитів та асоціацій збережеться).

Стратегія SINGLE_TABLE

Цю стратегію варто використовувати:

а) Тільки для простих завдань. У ситуаціях, коли нормалізація та обмеження NOT NULL є критичними, слід віддати перевагу стратегії №3 (JOINED). Має сенс замислитись, чи не краще в цьому випадку повністю відмовитися від успадкування та замінити його на делегування.

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

І на додаток до цього, на тебе чекає серйозна розмова з адміністратором БД.

Стратегія JOINED

Ця стратегія найефективніша в плані швидкості та CONSTRAINTS. Вона підійде у випадках, коли потрібні поліморфні запити та асоціації, але підкласи оголошують відносно багато нових полів.

Тут варто зазначити: рішення між JOINED та TABLE_PER_CLASS вимагає оцінки планів виконання запитів на реальних даних, оскільки ширина та глибина ієрархії успадкування можуть зробити вартість з'єднань (і, як наслідок, продуктивність) неприйнятними.

Особливо варто взяти до уваги те, що анотації наслідування неможливо застосувати до інтерфейсів.

2. EXPLICIT

Ще може бути ситуація, коли ти маєш ієрархію Entity-класів зі спільною стратегією зберігання в базі банних. Але з якихось причин ти не хочеш, щоб якийсь клас ієрархії повертався, коли робиться запит за базовим класом.

Для цього є інструкція:


@Polymorphism(type = PolymorphismType.EXPLICIT)

Якщо ми додамо її до класу Client:


@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
@Polymorphism(type = PolymorphismType.EXPLICIT)
class Client extends User {
   String address;
}

То HQL-запити будуть ігнорувати об'єкти цього класу під час запиту базового класу:


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

Цей запит поверне список об'єктів User та Employee, але не Client.