Mapim enum

Já descobrimos como mapear tipos de dados primitivos: usamos a anotação @Column e a anotação @Type . Mas nem todos os casos podem ser cobertos por essas anotações. E o caso mais comum é enum .

Os objetos Java enum podem ser armazenados no banco de dados de duas maneiras:

  • como um número
  • como uma corda

Vamos escrever um pequeno exemplo onde o usuário terá uma cor favorita, que é definida usando enum.


enum Color {
   RED,
   ORANGE,
   YELLOW,
   GREEN,
   BLUE,
   VIOLET
}

E adicione um campo de cor à classe User :


@Entity
@Table(name="user")
class User
{
   @Column(name="id")
   public Integer id;
 
   @Column(name="favorite_color")
   public Color favoriteColor;
 
   @Column(name="created_date")
   public Date createdDate;
}

Se quisermos que o Hibernate salve o tipo Color na base como números , então precisamos do campocor favoritaadicionar anotação:


@Enumerated(EnumType.ORDINAL)

Se quisermos que os valores sejam armazenados como strings , precisamos adicionar uma anotação:


@Enumerated(EnumType.STRING)

Exemplo:


@Entity
@Table(name="user")
class User
{
   @Column(name="id")
   public Integer id;
 
   @Enumerated(EnumType.ORDINAL) //value will be saved to the base as a number
   @Column(name="favorite_color")
   public Color favoriteColor;
 
   @Column(name="created_date")
   public Date createdDate;
}

Mapim Booleano

O segundo cenário útil é o mapeamento de tipo booleano. Aconteceu historicamente que o SQL não tem seu próprio tipo de dados para Boolean e qualquer coisa é usada lá.

As três opções mais comuns são:

  • 1 ou 0
  • 'F' ou 'T'
  • 'S' ou 'N'

Em geral, se você for projetar sua base, é melhor escrever o tipo BIT imediatamente. Bem, o mapeamento completo para ele ficará assim:


	@Column(name = "is_correct", columnDefinition = "BIT")
	@Type(type = "org.hibernate.type.NumericBooleanType")
    private Boolean isCorrect;

Bem, se você não está projetando o banco de dados, consulte a tabela acima e pense em como mapear corretamente os tipos que você precisa.

Campos calculados

Às vezes, o número de campos em uma classe Entity e o número de colunas em uma tabela não correspondem. Pode haver várias razões para isso.

O mais comum é quando existe algum campo em nossa classe Entity que não queremos salvar no banco de dados. Tudo fica claro com isso - basta adicionar a anotação @Transient a esse campo e o Hibernate irá ignorá-lo ao trabalhar com o banco de dados.

Exemplo:


@Entity(name = "Square")
public class Square {
           	@Id
           	public Long id;
 
           	public Integer width;
 
           	public Integer height;
 
           	@Transient
           	public Integer total;
}

Esta é uma boa opção, mas ao ler um objeto do banco de dados, o campo total será nulo. E gostaríamos que contivesse o produto largura x altura. Isso também pode ser feito no Hibernate. Existe uma anotação @Formula especial para isso .


@Entity(name = "Square")
public class Square {
           	@Id
           	public Long id;
 
           	public Integer width;
 
           	public Integer height;
 
           	@Formula(value = " width * height ")
          	public Integer total;
}

Esse campo não será salvo no banco de dados e, quando o objeto for lido do banco de dados, o valor calculado pela fórmula será gravado nele.

A consulta SQL ficará mais ou menos assim:

 SELECT id, width, height, (width* height) AS total FROM Square;

@Integrado

Outra anotação útil é @Embedded . Permite considerar os campos do objeto filho como campos da própria classe Entity.

Digamos que você tenha uma classe User e decida adicionar um endereço a ela:


@Entity
@Table(name="user")
class User
{
   @Column(name="id")
    public Integer id;
 
   @Column(name="user_address_country")
   public String country;
   @Column(name="user_address_city")
   public String city;
   @Column(name="user_address_street")
   public String street;
   @Column(name="user_address_home")
   public String home;
 
   @Column(name="created_date")
    public Date createdDate;
}

Tudo parece estar bem, mas do ponto de vista do Java, seria lógico colocar o endereço em uma classe separada. O endereço ainda é uma entidade separada. Mas como fazer isso se todas essas informações estão armazenadas no banco de dados na tabela do usuário?

A anotação @Embedded nos ajudará . Primeiro, criaremos a classe UserAddress e colocaremos todas as informações do endereço do usuário nela:


@Embeddable
class UserAddress
{
   @Column(name="user_address_country")
   public String country;
   @Column(name="user_address_city")
   public String city;
   @Column(name="user_address_street")
   public String street;
   @Column(name="user_address_home")
   public String home;
}

E então usamos um campo desta classe em nossa classe User :


@Entity
@Table(name="user")
class User
{
   @Column(name="id")
   public Integer id;
 
   @Embedded
   public UserAddress address;
 
   @Column(name="created_date")
   public Date createdDate;
}

Graças à anotação @Embedded , no momento de salvar o objeto, o Hibernate entenderá que os campos da classe UserAddress precisam ser tratados como campos da própria classe User .

Importante! Se você decidir adicionar dois campos UserAddress à sua classe User , usar @Embedded não funcionará mais: você terá campos duplicados e precisará separá-los de alguma forma. Isso é feito substituindo as anotações: usando a anotação @AttributeOverrides .

Eu quero que você saiba disso, mas não vamos entrar em detalhes aqui. Acho que isso é o suficiente para você quebrar a cabeça. Para os curiosos, posso deixar um link para a documentação oficial .