Qual é a melhor maneira de salvar enumerações em um banco de dados?
Eu sei que o Java fornece name()
e valueOf()
métodos para converter valores de enum em uma String e vice-versa. Mas existem outras opções (flexíveis) para armazenar esses valores?
Existe uma maneira inteligente de transformar enums em números únicos ( ordinal()
não é seguro de usar)?
Atualizar:
Obrigado por todas as respostas impressionantes e rápidas! Era como eu suspeitava.
No entanto, uma observação para 'toolkit'; Essa é uma maneira. O problema é que eu precisaria adicionar os mesmos métodos para cada tipo de Enum que eu criar. Há muito código duplicado e, no momento, o Java não suporta nenhuma solução para isso (um enum do Java não pode estender outras classes).
Respostas:
Nós não armazenar enumerações como valores ordinais numéricas mais; torna a depuração e o suporte muito difíceis. Armazenamos o valor real da enumeração convertido em string:
e depois leia novamente com:
O problema estava no passado, encarando o Enterprise Manager e tentando decifrar:
versos
o último é muito mais fácil. O primeiro exigia obter o código-fonte e localizar os valores numéricos atribuídos aos membros da enumeração.
Sim, é preciso mais espaço, mas os nomes dos membros da enumeração são curtos e os discos rígidos são baratos, e vale muito a pena ajudar quando você está tendo um problema.
Além disso, se você usar valores numéricos, estará vinculado a eles. Você não pode inserir ou reorganizar os membros sem precisar forçar os valores numéricos antigos. Por exemplo, alterando a enumeração Suit para:
teria que se tornar:
para manter os valores numéricos herdados armazenados no banco de dados.
Como classificá-los no banco de dados
A pergunta surge: digamos que eu queria ordenar os valores. Algumas pessoas podem querer classificá-las pelo valor ordinal da enumeração. Obviamente, ordenar os cartões pelo valor numérico da enumeração não tem sentido:
Essa não é a ordem que queremos - queremos em ordem de enumeração:
O mesmo trabalho necessário se você salvar valores inteiros será necessário se você salvar seqüências de caracteres:
Mas essa não é a ordem que queremos - queremos em ordem de enumeração:
Minha opinião é que esse tipo de classificação pertence à interface do usuário. Se você estiver classificando itens com base no valor de enumeração: está fazendo algo errado.
Mas se você realmente quiser fazer isso, eu criaria uma
Suits
tabela de dimensões:Dessa forma, quando você desejar alterar suas cartas para usar o Kissing Kings New Deck Order, poderá alterá-las para fins de exibição sem jogar fora todos os seus dados:
Agora, estamos separando um detalhe de programação interno (nome da enumeração, valor da enumeração) com uma configuração de exibição destinada aos usuários:
fonte
12.37 ms
a tomar12.3702 ms
. É isso que eu quero dizer com "no barulho" . Você executa a consulta novamente e é preciso13.29 ms
, ou11.36 ms
. Em outras palavras, a aleatoriedade do agendador de threads inundará drasticamente qualquer micro otimização que você teoricamente tenha que não seja de modo algum visível para ninguém de nenhuma maneira.A menos que você tenha motivos específicos de desempenho para evitá-lo, eu recomendaria o uso de uma tabela separada para a enumeração. Use integridade de chave estrangeira, a menos que a pesquisa extra realmente o mate.
Ternos tabela:
Tabela de jogadores
suit_id
) são independentes do valor da enumeração, o que ajuda você a trabalhar com os dados de outros idiomas também.fonte
public enum foo {bar}
quanto noCREATE TABLE foo (name varchar);
que pode facilmente ficar fora de sincronia.Eu argumentaria que o único mecanismo seguro aqui é usar o
name()
valor String . Ao escrever no banco de dados, você pode usar um sproc para inserir o valor e, ao ler, usar uma Visualização. Dessa maneira, se as enumerações mudarem, há um nível de indireção no sproc / view para poder apresentar os dados como o valor da enumeração sem "impor" isso no banco de dados.fonte
Como você diz, ordinal é um pouco arriscado. Considere, por exemplo:
Se você armazenou isso como ordinais, poderá ter linhas como:
Mas o que acontece se você atualizou o booleano?
Isso significa que todas as suas mentiras serão mal interpretadas como 'arquivo não encontrado'
Melhor usar apenas uma representação de string
fonte
Para um banco de dados grande, reluto em perder as vantagens de tamanho e velocidade da representação numérica. Costumo terminar com uma tabela de banco de dados representando o Enum.
Você pode reforçar a consistência do banco de dados declarando uma chave estrangeira - embora em alguns casos seja melhor não declarar isso como uma restrição de chave estrangeira, o que impõe um custo a cada transação. Você pode garantir consistência, periodicamente, verificando, no momento da sua escolha, com:
A outra metade dessa solução é escrever um código de teste que verifique se a enum Java e a tabela de enum do banco de dados têm o mesmo conteúdo. Isso é deixado como um exercício para o leitor.
fonte
enumID
tem quatro bytes, você tem três bytes extras por linha usando nomes. 3 bytes x 1 milhão de linhas são 3 MB.enumId
certamente cabe em dois bytes (enums mais longos não são possíveis em Java) e a maioria deles cabe em um único byte (que alguns DB suportam). O espaço economizado é insignificante, mas a comparação mais rápida e o comprimento fixo devem ajudar.Apenas armazenamos o próprio nome da enumeração - é mais legível.
Nós brincamos com o armazenamento de valores específicos para enumerações onde há um conjunto limitado de valores, por exemplo, essa enumeração que possui um conjunto limitado de status que usamos um caractere para representar (mais significativo que um valor numérico):
e quando você tem muitos valores, precisa ter um mapa dentro da sua enumeração para manter pequeno o método getFromXYZ.
fonte
Se salvar enumerações como seqüências de caracteres no banco de dados, você poderá criar métodos utilitários para (des) serializar qualquer enumeração:
fonte
Toda a minha experiência me diz que a maneira mais segura de persistir enumerações em qualquer lugar é usar valor ou código adicional de código (algum tipo de evolução da resposta do @jeebee). Este poderia ser um bom exemplo de uma ideia:
Agora você pode usar qualquer persistência referenciando suas constantes enum por seu código. Mesmo que você decida alterar alguns nomes de constantes, sempre poderá salvar o valor do código (por exemplo,
DWARF("dwarf")
paraGNOME("dwarf")
)Ok, mergulhe um pouco mais fundo com essa concepção. Aqui está um método utilitário, que ajuda a encontrar qualquer valor de enumeração, mas primeiro vamos estender nossa abordagem.
E deixe nosso enum implementá-lo:
Este é o momento do método de pesquisa mágica:
E use-o como um encanto:
Race race = resolveByCode(Race.class, "elf")
fonte
Eu enfrentei o mesmo problema em que meu objetivo é persistir o valor Enum String no banco de dados em vez do valor Ordinal.
Para superar esse problema, usei
@Enumerated(EnumType.STRING)
e meu objetivo foi resolvido.Por exemplo, você tem uma
Enum
classe:Na classe da entidade, defina
@Enumerated(EnumType.STRING)
:Enquanto você tenta definir seu valor como Banco de Dados, o valor da String será mantido no Banco de Dados como "
APPLE
", "ORANGE
" ou "LEMON
".fonte
Vários valores com relação OR para um campo de enumeração. O conceito para .NET com armazenamento de tipos de enum no banco de dados como um byte ou um int e usando FlagsAttribute no seu código.
http://blogs.msdn.com/b/efdesign/archive/2011/06/29/enumeration-support-in-entity-framework.aspx
fonte
Você pode usar um valor extra na constante de enumeração que possa sobreviver às alterações de nome e ao recurso das enumerações:
Para obter o ID da enumeração:
Para obter a enumeração de um ID:
Sugiro usar valores sem significado para evitar confusão se os nomes de enum precisarem ser alterados.
No exemplo acima, usei uma variante da "Numeração básica de linhas", deixando espaços para que os números provavelmente permaneçam na mesma ordem que as enumerações.
Essa versão é mais rápida do que usar uma tabela secundária, mas torna o sistema mais dependente do código e do conhecimento do código-fonte.
Para remediar isso, você também pode configurar uma tabela com os IDs de enumeração no banco de dados. Ou siga o caminho inverso e escolha IDs para as enumerações de uma tabela à medida que você adiciona linhas a ela.
Nota : Sempre verifique sempre se você não está projetando algo que deve ser armazenado em uma tabela de banco de dados e mantido como um objeto regular. Se você pode imaginar que precisa adicionar novas constantes à enum neste momento, quando a estiver configurando, isso é uma indicação de que é melhor criar um objeto regular e uma tabela.
fonte