JavaRush /Курсы /SQL & Hibernate /Дискриминатор

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

SQL & Hibernate
15 уровень , 2 лекция
Открыта

Описание

В предыдущей лекции ты видел, что 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. Просто и красиво.

@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

@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 "
)
Комментарии (8)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Руслан Никитин Уровень 109
2 февраля 2025
на @DiscriminatorFormula мой мозг всё
I'm Siberian Уровень 109 Expert
21 февраля 2025
"Но и это ещё не всё" 😁 Согласен, вроде понятно, но запоминательная функция всего уже покинула голову )
Олег Уровень 106 Expert
21 октября 2024
Вообще перестал понимать, о чём идёт речь.
Николай Уровень 109
4 апреля 2024
Для валидатора необходимо что бы поле Id было Long, а поле age Integer.
Max Dudin Уровень 6 Expert
15 октября 2023
"В предыдущей лекции ты видел, что Hibernate использует специальную колонку DTYPE VARCHAR для хранения имени Entity-класса." специально вернулся и перечитал. Ничего такого я там не увидел. =(
Anonymous #3272489 Уровень 92 Expert
20 октября 2023
он в прошлой лекции в самом начале в запросе на создание таблицы
Olga Shestakova Уровень 108 Expert
3 февраля 2023
В задаче просят INT id, а решение только с Long проходит
Владимир Уровень 108
8 июня 2023
У меня другой случай. Требуется int age, а валидируется только с Integer age