Описание

В предыдущей лекции ты видел, что 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 "
)
undefined
1
Задача
Модуль 4. Работа с БД, 15 уровень, 2 лекция
Недоступна
Стратегия Single Table
Посмотри на скрипт по созданию таблицы person. Создай три энтити-класса по этой таблице, которые описывают стратегию Single Table: кроме энтити Person должны быть созданы энтити-классы Client (с полем bank) и Employee (с полем company), которые унаследуй от Person.