Eu já vi várias perguntas, como esta , pedindo conselhos sobre como armazenar enumerações no DB. Mas eu me pergunto por que você faria isso. Então, digamos que eu tenho uma entidade Person
com um gender
campo e uma Gender
enumeração. Então, minha tabela de pessoa tem um gênero de coluna.
Além do motivo óbvio de impor a correção, não vejo por que criaria uma tabela extra gender
para mapear o que já tenho no meu aplicativo. E eu realmente não gosto de ter essa duplicação.
Respostas:
Vamos dar outro exemplo que é menos cheio de concepções e expectativas. Eu tenho um enum aqui, e é o conjunto de prioridades para um bug.
Qual valor você está armazenando no banco de dados?
Então, eu poderia estar armazenando
'C'
,'H'
,'M'
, e'L'
no banco de dados. Ou'HIGH'
assim por diante. Isso tem o problema de dados digitados em sequência . Há um conjunto conhecido de valores válidos e, se você não estiver armazenando esse conjunto no banco de dados, pode ser difícil trabalhar com ele.Por que você está armazenando os dados no código?
Você tem
List<String> priorities = {'CRITICAL', 'HIGH', 'MEDIUM', 'LOW'};
ou algo nesse sentido no código. Isso significa que você tem vários mapeamentos desses dados no formato correto (você está inserindo todos os limites no banco de dados, mas está exibindo-o comoCritical
). Agora, seu código também é difícil de localizar. Você vinculou a representação do banco de dados da ideia a uma sequência armazenada no código.Em qualquer lugar que você precisar acessar essa lista, é necessário ter duplicação de código ou uma classe com várias constantes. Nenhuma das quais são boas opções. Também não se deve esquecer que existem outros aplicativos que podem usar esses dados (que podem ser gravados em outros idiomas - o aplicativo da web Java possui um sistema de relatórios Crystal Reports usado e um trabalho em lote Perl alimentando dados). O mecanismo de relatório precisaria conhecer a lista de dados válida (o que acontece se não houver nada marcado em
'LOW'
prioridade e você precisar saber que essa é uma prioridade válida para o relatório?), E o trabalho em lotes terá informações sobre qual é o valor válido valores são.Hipoteticamente, você pode dizer "somos uma loja de idioma único - tudo está escrito em Java" e temos um único .jar que contém essas informações - mas agora isso significa que seus aplicativos estão fortemente acoplados entre si e que .jar contém os dados. Você precisará liberar a parte de relatório e a parte de atualização em lote junto com o aplicativo da Web cada vez que houver uma alteração - e espero que essa liberação ocorra sem problemas para todas as partes.
O que acontece quando seu chefe quer outra prioridade?
Seu chefe veio hoje. Há uma nova prioridade -
CEO
. Agora você precisa alterar todo o código , recompilar e reimplementar.Com uma abordagem 'enum-in-the-table', você atualiza a lista de enum para ter uma nova prioridade. Todo o código que obtém a lista extrai-o do banco de dados.
Os dados raramente ficam sozinhos
Com prioridades, os dados são inseridos em outras tabelas que podem conter informações sobre fluxos de trabalho ou sobre quem pode definir essa prioridade ou outros enfeites.
Voltando um pouco ao gênero, como mencionado na pergunta: O gênero tem um link para os pronomes em uso:
he/his/him
eshe/hers/her
... e você deseja evitar a codificação embutida no próprio código. E então seu chefe aparece e você precisa adicionar o'OTHER'
gênero (para simplificar) e relacionar esse gênero comthey/their/them
... e seu chefe vê o que o Facebook tem e ... bem, sim.Ao se restringir a um bit de dados do tipo string em vez de a uma tabela enum, você agora precisa replicar essa string em várias outras tabelas para manter esse relacionamento entre os dados e seus outros bits.
E quanto a outros datastores?
Não importa onde você armazena isso, o mesmo princípio existe.
priorities.prop
que tenha a lista de prioridades. Você lê esta lista em um arquivo de propriedades.Você pode ter um banco de dados de armazenamento de documentos (como o CouchDB ) que possua uma entrada para
enums
(e depois escreva uma função de validação em JavaScript ):Você pode ter um arquivo XML com um pouco de esquema:
A idéia central é a mesma. O próprio armazenamento de dados é onde a lista de valores válidos precisa ser armazenada e aplicada. Ao colocá-lo aqui, é mais fácil argumentar sobre o código e os dados. Você não precisa se preocupar em verificar defensivamente o que possui a cada vez (em maiúsculas ou minúsculas? Por que existe um
chritical
tipo nesta coluna? Etc ...) porque você sabe o que está recebendo de volta do armazenamento de dados. exatamente o que o armazenamento de dados espera que você envie de outra forma - e você pode consultar o armazenamento de dados para obter uma lista de valores válidos.O takeaway
O conjunto de valores válidos são dados , não código. Você não precisa se esforçar para DRY código - mas a questão da duplicação é que você está duplicando os dados no código, em vez de respeitar o seu lugar como dados e armazená-lo em um banco de dados.
Isso facilita a gravação de vários aplicativos no armazenamento de dados e evita ter instâncias nas quais você precisará implantar tudo o que estiver fortemente acoplado aos dados em si - porque você não acoplado seu código aos dados.
Isso torna os aplicativos de teste mais fáceis porque você não precisa testar novamente o aplicativo inteiro quando a
CEO
prioridade é adicionada - porque você não tem nenhum código que se preocupe com o valor real da prioridade.Ser capaz de raciocinar sobre o código e os dados independentemente um do outro facilita a localização e a correção de bugs durante a manutenção.
fonte
Qual destes você acha que é mais provável que cometa erros ao ler a consulta?
Ou
As pessoas criam tabelas enum no SQL porque acham que o último é mais legível - levando a menos erros ao escrever e manter o SQL.
Você poderia transformar o gênero em uma string diretamente
Person
, mas teria que tentar aplicar o caso. Você também pode aumentar o acerto de armazenamento da tabela e o tempo de consulta devido à diferença entre cadeias e números inteiros, dependendo de quão impressionante é o seu banco de dados ao otimizar as coisas.fonte
Não acredito que as pessoas ainda não mencionaram isso.
Chaves estrangeiras
Mantendo a enum no seu banco de dados e adicionando uma chave estrangeira na tabela que contém um valor de enum, você garante que nenhum código entre com valores incorretos para essa coluna. Isso ajuda a integridade dos dados e é o motivo mais óbvio pelo qual você deve ter tabelas para enumerações.
fonte
Estou no campo que concorda com você. Se você mantiver uma enumeração de Gênero em seu código e um tblGender em seu banco de dados, poderá ter problemas durante a manutenção. Você precisará documentar que essas duas entidades devem ter os mesmos valores e, portanto, todas as alterações feitas em uma também devem ser feitas na outra.
Você precisará passar os valores de enumeração para os procedimentos armazenados da seguinte maneira:
Mas pense em como você faria isso se mantivesse esses valores em uma tabela de banco de dados:
Os bancos de dados relacionais são criados com junções em mente, mas qual consulta é mais fácil de ler?
Aqui está outro exemplo de consulta:
Compare isso com isso:
Aqui está outro exemplo de consulta:
Observe que, neste exemplo, você precisaria converter a célula de gênero nos seus resultados de um int para um enum. Essas conversões são fáceis no entanto. Compare isso com isso:
Todas essas consultas são menores e mais fáceis de manter quando você pensa em manter as definições de enum fora do banco de dados.
fonte
Eu criaria uma tabela de gêneros pelo motivo de poder ser usada na análise de dados. Eu poderia procurar todas as pessoas do sexo masculino ou feminino no banco de dados para gerar um relatório. Quanto mais maneiras você visualizar seus dados, mais fácil será descobrir informações de tendências. Obviamente, essa é uma enumeração muito simples, mas para enumerações complexas (como os países do mundo ou estados), facilita a geração de relatórios especializados.
fonte
Primeiro, você precisa decidir se o banco de dados será usado apenas por um aplicativo ou se é possível que vários aplicativos o utilizem. Em alguns casos, um banco de dados nada mais é do que um formato de arquivo para um aplicativo (os bancos de dados SQLite costumam ser usados nesse sentido). Nesse caso, a duplicação de bits da definição de enum como uma tabela geralmente pode ser boa e pode fazer mais sentido.
No entanto, assim que você quiser considerar a possibilidade de ter vários aplicativos acessando o banco de dados, uma tabela para a enum faz muito sentido (as outras respostas abordam o porquê com mais detalhes). A outra coisa a considerar é que você ou outro desenvolvedor deseja examinar os dados brutos do banco de dados. Nesse caso, isso pode ser considerado outro uso de aplicativo (apenas aquele em que o medidor de laboratório é SQL bruto).
Se você tiver a enumeração definida no código (para uma verificação mais limpa do código e no tempo de compilação), bem como uma tabela no banco de dados, eu recomendaria adicionar testes de unidade para verificar se os dois estão sincronizados.
fonte
Quando você possui uma enumeração de código usada para direcionar a lógica de negócios no código, ainda deve criar uma tabela para representar os dados no banco de dados pelos diversos motivos detalhados acima / abaixo. Aqui estão algumas dicas para garantir que seus valores de banco de dados permaneçam sincronizados com os valores de código:
Não faça do campo de identificação na tabela uma coluna de identidade. Inclua ID e Descrição como campos.
Faça algo diferente na tabela que ajude os desenvolvedores a saber que os valores são semi-estáticos / vinculados a uma enumeração de código. Em todas as outras tabelas de pesquisa (geralmente onde os valores podem ser adicionados pelos usuários), normalmente tenho LastChangedDateTime e LastChangedBy, mas não tê-los em tabelas relacionadas à enumeração me ajuda a lembrar que eles só podem ser alterados pelos desenvolvedores. Documente isso.
Crie um código de verificação que verifique se cada valor na enumeração está na tabela correspondente e se apenas esses valores estão na tabela correspondente. Se você tiver "testes de integridade" automatizados de aplicativos que executam a pós-compilação, nele. Caso contrário, faça com que o código seja executado automaticamente na inicialização do aplicativo sempre que o aplicativo estiver sendo executado no IDE.
Criar produção entregar scripts SQL que fazem o mesmo, mas de dentro do banco de dados. Se criados corretamente, também ajudarão nas migrações do ambiente.
fonte
Depende também de quem acessa os dados. Se você tiver apenas um aplicativo que pode ser bom. Se você adicionar um data warehouse ou um sistema de relatórios. Eles precisarão saber o que esse código significa, qual é a versão editável para humanos do código.
Normalmente, a tabela de tipos não seria duplicada como uma enumeração no código. Você pode carregar a tabela de tipos em uma lista que é armazenada em cache.
Muitas vezes, digite ir e vir. Você precisaria de uma data para quando o novo tipo foi adicionado. Saiba quando um tipo específico foi removido. Exiba-o apenas quando necessário. E se um cliente quiser "transgênero" como gênero, mas outros não? Todas essas informações são melhor armazenadas no banco de dados.
fonte