Mapeamento de atributos

  • As entidades são convertidas para tabelas no banco..
  • Os atributos simples desta entidade são convertidos às colunas da respectiva tabela. Nesta seção vamos estudar como configura e utilizar as anotações nos atributos simples. -Todas as anotações estão presentes no pacote javax.persistence.*

@Column

Utilizamos esta anotação para configurar a coluna da tabela, quando não especificada as configurações default são aplicadas. A anotação @Column permite algumas configurações em suas propriedades:

  • name: Define o nome da coluna, o valor default é o nome da propriedade ou atributo;
  • unique: Informa se a coluna é chave única;
  • columnDefinition: Defini o código SQL utilizado para gerar a coluna, o valor default cria a coluna com o tipo inferido.
  • length: Tamanho da coluna, o valor default é 255, usado apenas em atributos com tipo String;
  • precision: Informa a precisão da coluna decimal, usado apenas em atributos com tipo numérico decimal;
  • scale: Define o número de casas decimais, usado apenas em atributos com tipo numérico decimal;
  • table: Nome da tabela que contém está coluna;
  • nullable: Informa se o valor pode ser null;
  • updatable: Informa se a coluna deve ser incluída no SQL de update, o valor default é true;
  • insertable: Informa se a coluna deve ser incluída no SQL de insert, o valor default é true;

Na documentação encontramos alguns exemplos de uso desta anotação:

@Column(name="DESC", nullable=false, length=512)
public String getDescription() {
return description;
}

@Column(name="DESC",columnDefinition="CLOB NOT NULL", table="EMP_DETAIL")
@Lob public String getDescription() {
return description;
}

@Column(name="ORDER_COST", updatable=false, precision=12, scale=2)
public BigDecimal getCost() {
return cost;
}

@Enumerated

Utilizamos esta anotação em atributos do tipo enum.

public enum Sexo {
    MASCULINO,
    FEMININO
}

Nota

Essa anotação permite dois valores ao parâmetro EnumType:

  • @Enumerated(EnumType.STRING): Armazena a propriedade como um texto. Neste exemplo, seria persistido o texto "MASCULINO" ou "FEMININO", respectivamente para identificar o Sexo.MASCULINO e Sexo.FEMININO.
  • @Enumerated(EnumType.ORDINAL): Armazena a propriedade como um inteiro. Neste exemplo, seriam persistido 0 ou 1, respectivamente para identificar o Sexo.MASCULINO e Sexo.FEMININO.

Mapeamento na entidade:

@Enumerated(EnumType.STRING)
private Sexo sexo;

@Transient

Há situações onde não temos interesse em persiste uma propriedade da entidade, pois podemos calcular o seu valor a partir de outro atributo, por exemplo calcular a idade sabendo de sua data de nascimento.

 @Entity
 public class Pessoa {
     @Transient
     private int idade;     
     private LocalDate dataDeNascimento;

Neste exemplo, o atributo idade não será persistido no banco de dados.

@Lob

Esta anotação é utilizada em atributos que representam uma grande quantidade de bytes para armazenamento, por exemplo imagens ou texto longos.

Em geral utilizada com @Basic, para sugerir que o atributo seja carregado sob demanda.

@Entity
public class Postagem {
    @Lob
    @Basic(fetch = FetchType.LAZY)
    private String textoLongo;

Idealmente, devemos utilizar esta anotação também em conjunto com as anotações de relacionamento (@OneToMany e @ManyToMany).

@Basic

Esta anotação possui o parâmetro fetch(), que especifica se a propriedade é carregada sob demanda @Basic(fetch = FetchType.LAZY) ou imediatamente @Basic(fetch = FetchType.EAGER).

@Basic(fetch=LAZY)
protected String getName() { return name; }

Entretanto, o comportamento dessa propriedade não é garantido quando configurado com fetch = FetchType.LAZY, pois o provedor JPA pode, por questões de performance, carregar o valor do atributo.

@Entity
public class Pessoa {
    @Lob
    @Basic(fetch = FetchType.LAZY)
    private byte[] imagem;
}

O outro parâmetro é o optional(), que define se o atributo pode, ou não, ser nulo.

@Temporal

Quanto temos propriedades que manipulam valores relacionados a tempo, usamos esta anotação. Podemos utilizá-la em propriedades to tipo java.util.Date ou java.util.Calendar.

@Entity
public class Pessoa {
  @Temporal(TemporalType.DATE)
  private Date dataDoNascimento;
}

Neste exemplo, o atributo dataDoNascimento é armazenado no banco como um tipo DATE do SQL.

Essa anotação permite três valores ao parâmetro TemporalType:

  • @Temporal(TemporalType.DATE): Recupera apenas a data (dia, mês e ano);
  • @Temporal(TemporalType.TIME): Recupera apenas a hora (hora, minuto e segundo);
  • @Temporal(TemporalType.TIMESTAMP): Recupera a data e hora (dia, mês, ano, hora, minuto e segundo).

@ElementCollection

Define uma coleção de instâncias de um tipo de dados ou classe embeddable. Deve ser especificado se a coleção está a sendo mapeada para uma tabela de coleção.

@Entity
public class Pessoa {
    @ElementCollection
    @CollectionTable(name = "Telefones")
    private List<String> telefones;
}

Neste exemplo, a entidade Pessoa possui uma propriedade multivalorada. Será gerada uma tabela Telefones.

@Embeddable e @Embedded

@Entity
class Pessoa{
  private String nome;
  @Embedded
  @AttributeOverride(name=valor,column=@Column(name=cpf-pessoa))
  private CPF cpf;
}

@Embeddable
class CPF{
  private String valor;

  public String simples(){
    return valor; //12345678910
  }
  public String formatado(){
    return valor; //123.456.789-10
  }
  public boolean valido(){
      return true; //false
  }
}

@Converter

Quando temos que armazenar um atributo LocalDate em uma coluna Date ou uma LocalDateTime em uma coluna TIMESTAMP, precisamos definir um mapeamento para java.sql.Date ou java.sql.Timestamp.

Para criar um conversor de atributos para LocalDate e LocalDateTime, precisamos de uma classe que implemente AttributeConverter. Na classe ConvertLocalDate estamos convertendo um tipo LocalDate para java.sql.Date.

@Converter(autoApply = true)
public class ConvertLocalDate implements AttributeConverter<LocalDate, Date> {

    @Override
    public Date convertToDatabaseColumn(LocalDate attribute) {
        if (attribute == null) {
            return null;
        }
        return Date.valueOf(attribute);
    }
    @Override
    public LocalDate convertToEntityAttribute(Date dbData) {
        if (dbData == null) {
            return null;
        }
        return dbData.toLocalDate();
    }
}

Na entidade, usamos a anotação @Convert para identificar qual conversor será utilizado.

@Entity
public class Pessoa implements Serializable{

@Temporal(value = TemporalType.DATE)
@Convert(converter = ConvertLocalDate.class)
private LocalDate nascimento;

Chave composta

Temos duas estratégias @EmbeddedId e @IdClass.

Nota: A classe de chave primária, deve atender aos seguintes requisitos:

  1. Ela deve ser serializável;
  2. Ela deve ter um construtor sem argumento e público;
  3. Ela deve implementar os métodos equals() e hashCode()

A autogeração de valores não é suportada para chaves compostas.

@EmbeddedId

Embute a classe de chave primária diretamente na classe bean. Usada em conjunto com a @javax.persistence.Embeddable. Possui 2 formas:

  • Especificar os mapeamentos @Column
  • Utilizar @AttributeOverrides
@Embeddable
public class PessoaPK implements Serializable{
@Column(name=PESSOA_NOME) private String nome;
@Column(name=PESSOA_IDADE) private int idade;
public PessoaPK(){}
...
public boolean equals(Object obj){...}
public int hashCode(){}
}

Na entidade

@Entity
public class Pessoa implements Serializable{
}
private PessoaPK pk;
@EmbeddedId
public PessoaPK getPk(){return pk;}

A segunda forma fazendo uso da anotação @AttributeOverrides. Caso você não queira utilizar o @Column na classe de chave primária. Não precisa do @Column na classe anotada com @Embeddable (PessoaPK).

@Entity
public class Pessoa implements Serializable{
  private PessoaPK pk;
}
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name=nome,column=@Column(name=PESSOA_NOME)),
@AttributeOverride(name=idade,column=@Column(name=PESSOA_IDADE)) })
public PessoaPK getPk(){return pk;}

@IdClass

public class PessoaPK implements Serializable{ private String nome;
         private int idade;
         public PessoaPK(){}
...
public boolean equals(Object obj){...} public int hashCode(){}
}

Na entidade

@Entity
@IdClass(PessoaPK.class)
public class Pessoa implements Serializable{
private String nome;
private int idade;
@Id
public String getNome(){return nome;}
@Id
public int getIdade(){return idade;}

Nota:

Em ambos os casos de uso de chave composta para realizar uma consulta devemos passar uma referência da classe que representa a chave composta.

PessoaPK pk = new PessoaPK("Outro Aluno", 26); Pessoa p = entityManager.find(Pessoa.class, pk);

results matching ""

    No results matching ""