Trabalhando com JPA e enumerações
21/06/2010 | Por Samuel Delfim | Categoria: DESENVOLVIMENTO JAVAOlá 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.
1 2 3 | 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:
1 2 | 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:
1 2 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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…