Enumerated
Explicação
A anotação @Enumerated do JPA é utilizada para mapear atributos do tipo enum em entidades, definindo como seus valores serão armazenados no banco de dados. Existem duas opções principais para o tipo de armazenamento: EnumType.ORDINAL e EnumType.STRING.
@Enumerated
EnumType.ORDINALarmazena o valor do enum como um número inteiro, representando o índice da constante, o que pode ser suscetível a problemas se o enum for alterado (adicionar ou remover valores).EnumType.STRINGarmazena o nome da constante do enum como uma string, oferecendo maior clareza e estabilidade, pois o valor armazenado não depende da posição do enum.
Essa escolha afeta diretamente a forma como os dados são persistidos e a flexibilidade de alterações no código ao longo do tempo.
Isso deve funcionar bem como uma introdução ao tema.
Cenário:
Imagine que temos uma entidade Cliente com os atributos id, nome e estadoCivil, sendo que o estado civil é representado por um tipo enumerado.
Enumeração:
Primeiro, definimos o enum que representa os estados civis:
public enum EstadoCivil {
SOLTEIRO, CASADO, DIVORCIADO;
}
Classe Cliente:
Aqui está a classe Cliente, com a anotação @Enumerated aplicada ao atributo estadoCivil:
import javax.persistence.*;
@Entity
public class Cliente {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String nome;
@Enumerated(EnumType.STRING) // Especificando que o valor será armazenado como uma string
private EstadoCivil estadoCivil;
// Lombok ou Getters e Setters
}
Particularidades:
- ORDINAL:
- Se usarmos
EnumType.ORDINAL, o JPA vai armazenar o valor do enum como o índice da constante. Ou seja, o primeiro valor será 0, o segundo 1, e assim por diante.
Exemplo:
@Enumerated(EnumType.ORDINAL)
private EstadoCivil estadoCivil;
Nesse caso, o banco de dados armazenaria os valores como números inteiros:
SOLTEIRO-> 0CASADO-> 1DIVORCIADO-> 2
Cuidado: Isso pode gerar problemas se o enum for alterado (como adicionar ou remover valores), pois os números podem mudar e isso afetaria os dados já armazenados.
- STRING:
- Usando
EnumType.STRING, o JPA armazena o nome da constante do enum como uma string no banco de dados.
Exemplo:
@Enumerated(EnumType.STRING)
private EstadoCivil estadoCivil;
Nesse caso, o banco de dados armazenaria os valores como strings:
SOLTEIROCASADODIVORCIADO
Vantagem: Usar STRING é mais seguro, pois o valor do enum (nome da constante) permanece claro e não depende de índices numéricos que podem mudar se o enum for alterado.
Resumo:
EnumType.ORDINAL: armazena o índice (inteiro) da constante do enum.EnumType.STRING: armazena o nome da constante do enum como string, o que é mais claro e flexível.
A escolha entre ORDINAL e STRING depende do contexto e da necessidade de manter a integridade dos dados ao longo do tempo.
Converter ID
Se você deseja armazenar o ID do enum no banco de dados (como uma letra abreviada, por exemplo, S, C, D), você pode usar a anotação @Enumerated juntamente com um conversor personalizado.
Vamos adicionar um atributo id ao enum e criar um conversor para mapear o valor para o banco de dados.
- Definindo o enum com ID:
Adicionamos um atributo
idpara representar o código abreviado de cada estado civil.
public enum EstadoCivil {
SOLTEIRO("S"),
CASADO("C"),
DIVORCIADO("D"),
VIÚVO("V");
private final String id;
EstadoCivil(String id) {
this.id = id;
}
public String getId() {
return id;
}
public static EstadoCivil fromId(String id) {
for (EstadoCivil estado : values()) {
if (estado.getId().equals(id)) {
return estado;
}
}
throw new IllegalArgumentException("Id não encontrado: " + id);
}
}
Aqui, cada constante do enum tem um código de identificação (id) associado, como S para SOLTEIRO, C para CASADO, etc.
- Criando um conversor personalizado:
Agora, você pode criar um conversor JPA para armazenar o código (
id) do enum no banco de dados, usando a interfaceAttributeConverter.
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
@Converter(autoApply = true) // autoApply significa que o conversor será aplicado automaticamente em qualquer atributo do tipo EstadoCivil
public class EstadoCivilConverter implements AttributeConverter<EstadoCivil, String> {
@Override
public String convertToDatabaseColumn(EstadoCivil estadoCivil) {
return estadoCivil != null ? estadoCivil.getId() : null;
}
@Override
public EstadoCivil convertToEntityAttribute(String dbData) {
return dbData != null ? EstadoCivil.fromId(dbData) : null;
}
}
- O método
convertToDatabaseColumnconverte o enum para o código (id) quando o valor é persistido no banco. - O método
convertToEntityAttributefaz o oposto, convertendo o código de volta para o valor doenumao carregar os dados do banco.
- Aplicando o conversor na entidade
Cliente: Agora você pode aplicar a anotação@Enumeratede o conversor na classeCliente.
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Convert;
@Entity
public class Cliente {
@Id
private Long id;
private String nome;
@Convert(converter = EstadoCivilConverter.class)
private EstadoCivil estadoCivil;
// Getters e setters
}
A anotação @Convert especifica que o conversor EstadoCivilConverter será utilizado para o atributo estadoCivil.
No banco de dados
O banco de dados agora armazenará os valores como S, C, D, ou V, ao invés de salvar o nome completo do enum.
Por exemplo:
SOLTEIROserá salvo comoSCASADOserá salvo comoCDIVORCIADOserá salvo comoDVIÚVOserá salvo comoV
Vantagens
- O banco de dados armazena valores mais compactos e legíveis (letras em vez de strings longas).
- Você ainda mantém a flexibilidade do enum em código (com os nomes completos).
Essa estratégia garante que o código seja mais conciso e facilita a conversão entre o banco de dados e os valores do enum de forma transparente.