Relacional

Enumerated

Explorando a relação entre classes e entidades

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:

  1. 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 -> 0
  • CASADO -> 1
  • DIVORCIADO -> 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.

  1. 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.

  1. 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.

  1. 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 interface AttributeConverter.
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 do enum ao carregar os dados do banco.
  1. Aplicando o conversor na entidade Cliente: Agora você pode aplicar a anotação @Enumerated e o conversor na classe Cliente.
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 como S
  • CASADO será salvo como C
  • DIVORCIADO será salvo como D
  • VIÚVO será salvo como V

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.