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.ORDINAL
armazena 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.STRING
armazena 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:
SOLTEIRO
CASADO
DIVORCIADO
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
id
para 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
convertToDatabaseColumn
converte o enum para o código (id
) quando o valor é persistido no banco. - O método
convertToEntityAttribute
faz o oposto, convertendo o código de volta para o valor doenum
ao carregar os dados do banco.
- Aplicando o conversor na entidade
Cliente
: Agora você pode aplicar a anotação@Enumerated
e 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:
SOLTEIRO
será salvo comoS
CASADO
será salvo comoC
DIVORCIADO
será salvo comoD
VIÚVO
será 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.