Olá pessoal,
A bastante tempo não escrevo nada, mas hoje surgiu um assunto que acho ser uma pedra no sapato de vários desenvolvedores e arquitetos.
Enumerações, como o nome indica, são listas de valores associados a um conceito. Em java enumerações são subclasse da classe java.lang.Enum. Trabalhar com enumeração facilita bastante o trabalho do desenvolvedor, uma vez que fornece uma maneira de trabalhar com uma lista de valores finitas e trabalhar com tipos fortes em java.
Vejamos um exemplo simples de como isto pode ser um problema em sistemas.
public enum Sexo {
MASCULINO, FEMININO;
}
Ao realizar o mapeamento desta enumeração com JPA 1.0 utilizamos normalmente a anotação @Enumerated. Com esta anotação sem nenhum parâmetro ou passando o parâmetro EnumType.ORDINAL, o valor a ser persistido no banco seria:
MASCULINO.ordinal() == 0
FEMININO.ordinal() == 1
Uma das desvantagens desta abordagem é o problema do valor persistido não ser significante para o negócio, o que gera a necessidade de dicionário de dados. Outra desvantagem é o fato de não poder adicionar novos valores no começo e no meio da enumeração uma vez que já existem dados gravados com estes valores no banco.
Outra abordagem seria utilizar a anotação @Enumerated passando como parâmetro o EnumType.STRING. Com esta abordagem o valor a ser persistido passa a ser o método name da enumeração que é mostrado abaixo:
MASCULINO.name = "MASCULINO"
FEMININO.name = "FEMININO"
Esta abordagem também possui alguns problemas. O maior deles é a briga que vc terá com qualquer DBA a respeito do que deveria ser gravado no campo. O que qualquer DBA falará é que deveria ser gravado no banco os valores ‘M’ ou ‘F’ para ter menos gasto de memória e melhor indexação do campo.
Uma abordagem que acho a melhor seria gravar no banco o valor ‘M’ ou ‘F’, mas continuar trabalhando com a enumeração com os nomes MASCULINO e FEMININO.
Uma maneira de realizarmos esta modificação no código para funcionar desta maneira é mostrada abaixo:
Enumeração:
public enum SexoEnum {
MASCULINO("M"), FEMININO("F");
private final String value;
SexoEnum(String value) {
this.value = value;
}
public static SexoEnum fromValue(String value) {
if (value != null) {
for (SexoEnum sexo : values()) {
if (sexo.value.equals(value)) {
return sexo;
}
}
}
throw new IllegalArgumentException("Sexo invalido: " + value);
}
public String toValue() {
return value;
}
}
Na classe a ser mapeada o código ficaria próximo ao exemplo abaixo:
@Entity
public class Pessoa {
@Column(length = 1)
private String sexo;
@Transient
public SexoEnum getSexoEnum() {
return SexoEnum.fromValue(sexo);
}
public void setSexoEnum(SexoEnum sexoEnum) {
this.sexo = sexo.toValue();
}
}
Mapeando desta maneira trabalhamos então com o melhor dos dois mundos. Outra maneira bastante interessante de realizar o mapeamento seria a utilização do UserType do Hibernate, mas falamos disto em outro post.
Mais informações podem ser encontradas em http://www.vineetmanohar.com/2010/01/3-ways-to-serialize-java-enums.
É isto aí pessoal. Qualquer problema avisem…











Perfeita sua abordagem !!!
como vc ja usa a anotaçao no campo, entao realmente seria necessaria a anotaçao transiente no metodo ?
Olá Rena,
Veja que o método deve ser transiente, pois ele não tem o mesmo nome do campo persistido. Este método apenas abstrai o campo persistido. Qualquer problema avise…
Samuel,
E em casos onde já tenho uma base criada onde o campo onde quero aplicar o enum é númerico?
Por exemplo:
1 (Carro), 2(Caminhão)…
public enum Sexo {
MASCULINO, FEMININO;
}
Ao realizar o mapeamento desta enumeração com JPA 1.0 utilizamos normalmente a anotação @Enumerated. Com esta anotação sem nenhum parâmetro ou passando o parâmetro EnumType.ORDINAL, o valor a ser persistido no banco seria:
MASCULINO.ordinal() == 0
FEMININO.ordinal() == 1
Você tem que fazer deste jeito.