Descrição

Na lição anterior, você viu que o Hibernate usa uma coluna especial DTYPE VARCHAR para armazenar o nome de uma classe Entity. Essa coluna é chamada de discriminador . Ele é usado para determinar sem ambiguidade qual classe criar para uma determinada linha no banco de dados.

Você pode manipular esta coluna com a anotação @DiscriminatorColumn . Exemplo:

@DiscriminatorColumn(name="column_name",   discriminatorType = DiscriminatorType.INTEGER)

De acordo com a especificação JPA, um discriminador pode ter os seguintes tipos:

  • CORDA
  • CARACTERES
  • INTEIRO

No entanto, o Hibernate permite que você expanda um pouco essa lista. Ele suporta estes tipos Java: String, char, int, byte, short, boolean.

Se usarmos o tipo INTEGER, como codificar o nome da classe Entity nele? Para isso, outra anotação é utilizada - @DiscriminatorValue .

Veja um exemplo:

@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;
}

No exemplo acima, dissemos ao Hibernate que o discriminador usará a coluna user_type, que armazenará números. Se armazenar o valor 1, significa que o tipo de linha é Funcionário, se 2 for armazenado, o tipo de linha é Cliente. Simples e bonito.

@DiscriminatorValue

Mas isso não é tudo. Você pode dizer ao Hibernate como interpretar o tipo de uma string quando seu discriminador é NULL.

Na verdade, é muito simples. Você especifica o valor nulo para a anotação @DiscriminatorValue . Por exemplo, assim:

@DiscriminatorValue("null")

Exemplo de classe:

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

Dissemos ao Hibernate que qualquer linha da tabela que tenha NULL na coluna user_type deve ser interpretada como um objeto do tipo User.

Mas isso não é tudo. Há outro valor interessante para a anotação @DiscriminatorValue.

Aqui está isto:

@DiscriminatorValue("not null")

Exemplo de classe:

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

Com esta anotação, dissemos ao Hibernate que qualquer linha da tabela com um valor não NULL na coluna user_type deve ser interpretada como um objeto do tipo User. Mas isso é apenas para o caso de não ser encontrada uma classe que tenha o número necessário explicitamente especificado.

É assim que vai funcionar para diferentes valores dos discriminadores:

  • 0 - cria um objeto do tipo User
  • 1 - crie um objeto do tipo Funcionário
  • 2 - crie um objeto do tipo Cliente
  • 3 - crie um objeto do tipo User
  • 4 - crie um objeto do tipo User

@DiscriminatorFormula

Mas isso não é tudo. Para nosso discriminador, podemos especificar uma fórmula inteira pela qual ele calculará os valores para a anotação @DiscriminatorValue .

Existe uma anotação especial para isso, ela se chama @DiscriminatorFormula .

Exemplo:

@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;
}

Os valores retornados por @DiscriminatorFormula serão comparados pelo Hibernate com os valores especificados nas anotações @DiscriminatorValue . Com ele, você pode escrever cenários bastante complexos:

@DiscriminatorFormula(
           	"case when address is not null " +
           	"then 'Client' " +
           	"else (" +
           	"   case when occupation is not null " +
           	"   then 'Employee' " +
           	"   else 'Unknown' " +
           	"   end) " +
           	"end "
)