JavaRush /Курси /All lectures for UA purposes /Дискримінатор

Дискримінатор

All lectures for UA purposes
Рівень 1 , Лекція 607
Відкрита

1. Опис

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

Ти можеш керувати цією колонкою за допомогою анотації @DiscriminatorColumn. Приклад:


@DiscriminatorColumn(name="ім'я_колонки", discriminatorType = DiscriminatorType.INTEGER)

Відповідно до специфікації JPA дискримінатор може мати такі типи:

  • STRING
  • CHAR
  • INTEGER

Але Hibernate дозволяє трохи розширити цей список. Він підтримує такі Java-типи: String, char, int, byte, short, boolean.

Якщо ми використовуємо тип INTEGER, то як кодувати ім'я Entity-класу? Для цього використовується ще одна анотація — @DiscriminatorValue.

Подивися приклади:


@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="user_type", discriminatorType = DiscriminatorType.INTEGER)
@Entity
class User {
  int id;
  String name;
  LocalDate birthday;
}

@Entity
@DiscriminatorValue("1")
class Employee extends User {
 String occupation;
 int salary;
 LocalDate join;
}

@Entity
@DiscriminatorValue("2")
class Client extends User {
   String address;
}

У прикладі вище ми вказали Hibernate, що для дискримінатора використовуватиметься колонка user_type, яка зберігатиме числа. Якщо у ній зберігається значення 1, це означає, що тип рядка — Employee, якщо зберігається 2, то тип рядка — Client. Просто та красиво.

2. @DiscriminatorValue

Але це ще не все. Ти можеш вказати Hibernate, як інтерпретувати тип рядка, коли його дискримінатор дорівнює NULL.

Насправді це дуже просто. Ти вказуєш значення null в анотації @DiscriminatorValue. Наприклад, так:


@DiscriminatorValue("null")

Приклад класу:


@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="user_type", discriminatorType = DiscriminatorType.INTEGER)
@DiscriminatorValue("null")
@Entity
class User {
  int id;
  String name;
  LocalDate birthday;
}

Ми вказали Hibernate, що будь-який рядок таблиці, де в колонці user_type стоїть NULL, має бути інтерпретований як об'єкт типу User.

Але це ще не все. Є ще одне цікаве значення в анотації @DiscriminatorValue.

Ось таке:


@DiscriminatorValue("not null")

Приклад класу:


@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="user_type", discriminatorType = DiscriminatorType.INTEGER)
@DiscriminatorValue("not null")
@Entity
class User {
  int id;
  String name;
  LocalDate birthday;
}

За допомогою цієї анотації ми вказали Hibernate, що будь-який рядок таблиці, де в колонці user_type стоїть значення не NULL, має бути інтерпретована як об'єкт типу User. Але це тільки для випадку, якщо не буде знайдено клас, який має явно вказаний потрібний номер.

Так це працюватиме для різних значень дискримінаторів:

  • 0 — створюємо об'єкт типу User
  • 1 — створюємо об'єкт типу Employee
  • 2 — створюємо об'єкт типу Client
  • 3 — створюємо об'єкт типу User
  • 4 — створюємо об'єкт типу User

3. @DiscriminatorFormula

Але це ще не все. Для нашого дискримінатора ми можемо вказати цілу формулу, за якою він обчислюватиме значення для анотації @DiscriminatorValue.

Для цього є спеціальна анотація, вона так і називається @DiscriminatorFormula.

Приклад:


@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="user_type", discriminatorType = DiscriminatorType.INTEGER)
@DiscriminatorFormula("case when ‘join’ is not null then 1 else 2 end")
@Entity
class User {
  int id;
  String name;
  LocalDate birthday;
}

@Entity
@DiscriminatorValue("1")
class Employee extends User {
 String occupation;
 int salary;
 LocalDate join;
}

@Entity
@DiscriminatorValue("2")
class Client extends User {
   String address;
}

Значення, які повертає @DiscriminatorFormula, будуть порівнюватися Hibernate зі значеннями, вказаними в інструкціях @DiscriminatorValue. З її допомогою можна записувати досить складні сценарії:


@DiscriminatorFormula(
           "case when address is not null " +
           "then 'Client'" +
           "else ("+
           " case when occupation is not null " +
           " then 'Employee' " +
           "else 'Unknown'" +
           "end)" +
           "end"
)
Коментарі (1)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
Олександр Рівень 111
22 серпня 2024
В умові задачі явно не вказано, але поля класу Person мають бути чітко оголошені так:

    private Long id;
    private String name;
    private Integer age;
Інші варіанти Валя не приймає. Саме цікаве, що в підказках при неуспішній валідації сказано, що id та age мають бути типу int)))))))