De um modo geral, é uma prática recomendada permitir campos criados pelo usuário em um banco de dados para um aplicativo da web?
Por exemplo, estou fazendo um webapp de inventário doméstico para minha esposa e ela desejará definir seus próprios campos para itens diferentes. Eu estava planejando permitir que ela criasse categorias de itens e adicionasse "recursos" a essas categorias. Os recursos seriam apenas a chave / valor armazenado como seqüências de caracteres. Dessa forma, se ela tivesse uma categoria chamada "CDs de áudio", por exemplo, ela poderia adicionar recursos para itens como "artista", "faixas" etc. etc. Em outra categoria, como "móveis", ela poderia adicionar recursos para itens como "material "(madeira, plástico, etc). Qualquer item pode pertencer a uma (ou várias) categorias, adicionando esses recursos ao item.
Posso ver problemas em que a pesquisa por esses recursos requer comparações de strings, não há validação de dados etc. Seguindo a metodologia ágil, talvez seja melhor apenas que ela apresente novas categorias e atributos e eu precisaria criar novas tabelas como nós vamos. No meu exemplo, é uma pequena base de usuários (2 de nós) e a quantidade de registros criados seria pequena, portanto não muito ruim.
De um modo geral, como as pessoas lidam com algo assim na "vida real"?
Respostas:
Quando você começa a "campos definidos pelo usuário", como é freqüentemente encontrado em rastreadores de bugs, gerenciamento de recursos do cliente e ferramentas de negócios similares, é que eles não recebem backup de uma tabela com vários bilhões de campos (se houver, provavelmente é um problema de próprio).
Em vez disso, o que você encontra são os designs da tabela Valor do atributo da entidade e a ferramenta de administração associada para gerenciar os atributos válidos.
Considere a seguinte tabela:
Isso ocorre após você adicionar alguns atributos. Em vez de
attr1
fingir que lêartist
outracks
ougenre
ou quaisquer atributos que a coisa tenha. E em vez de 5, e se fosse 50. Claramente isso é incontrolável. Também requer uma atualização do modelo e reimplementação do aplicativo para manipular um novo campo. Não é ideal.Agora considere a seguinte estrutura de tabela:
Você tem a sua coisa com seus campos básicos. Você tem mais duas mesas. Um com os atributos. Cada campo é uma linha na
attr
tabela. E depois há othing_attr
com um par de chaves estrangeiras relacionadas àthing
mesa e àattr
mesa. E isso então tem um campo de valor onde você armazena qualquer que seja o valor do campo para essa entidade.E agora você tem uma estrutura em que a tabela attr pode ser atualizada em tempo de execução e novos campos podem ser adicionados (ou removidos) rapidamente, sem impacto significativo no aplicativo em geral.
As consultas são um pouco mais complexas e a validação também se torna mais complexa (procedimentos armazenados descolados ou todo o lado do cliente). É uma troca de design.
Considere também a situação em que algum dia você precisará fazer uma migração e voltar ao aplicativo para descobrir que agora existem meia dúzia de atributos a mais do que o esquema que você distribuiu originalmente. Isso cria migrações e atualizações feias, em que a tabela Valor do atributo da entidade, quando usada corretamente, pode ser mais limpa. (Nem sempre, mas pode ser.)
Se você estiver trabalhando com o sabor apropriado do banco de dados nosql, provavelmente poderá fazer isso (observe que o sabor apropriado do nosql para isso provavelmente seria um armazenamento de valor-chave que é, assim, a tabela EAV para os relacionais descritos acima) sem muita dificuldade. No entanto, ele vem com todos os compromissos do nosql, que são descritos em outros lugares em grandes detalhes.
Se você estiver trabalhando em um banco de dados relacional - precisará do esquema. Adicionar a coluna dinamicamente significa que algum subconjunto das seguintes coisas é verdadeiro:
select *
e, em seguida, fazendo um código complexo para descobrir quais são realmente os dados (consulte ResultSetMetaData do Java ) e armazenando-os em um mapa ( ou algum outro tipo de dados - mas não campos agradáveis no código). Isso então descarta um pouco de segurança de digitação e tipo que você possui com a abordagem tradicional.hasdate
campo para armazenar um registro de data e hora já foi definida comohasdate
um booleano para uma correspondência bem-sucedida ... e sua atualização é interrompida.varchar2
vstext
e similares. Seu código para adicionar a coluna funcionaria no MySQL, mas não no Postgres, Oracle ou SQL Server.delete * from students
, mas não pode realmente atrapalhar o banco de dados de maneiras ruins). O número de coisas que podem dar errado com o acesso ao esquema de um acidente ou de atividades maliciosas disparam.Isso realmente se resume a "não fazer". Se você realmente deseja isso, siga um padrão conhecido da estrutura da tabela EAV ou um banco de dados totalmente dedicado a essa estrutura. Não permita que as pessoas criem campos arbitrários em uma tabela. As dores de cabeça simplesmente não valem a pena.
fonte
Fazer isso bem é difícil.
Para um aplicativo único como o que você está planejando, é possível adicionar uma coluna para cada campo e fornecer uma interface do usuário que torne a definição de campo por usuários não treinados mais segura do que fornecer a eles uma linha de comando SQL. Ou você pode seguir o temido padrão Entidade-Atributo-Valor , que é uma resposta clássica, embora um tanto assustadora, a esse tipo de problema. Construindo a UI para definir campos EAV é geralmente muito mais complexo do que para as colunas de banco de dados, e as consultas pode ficar muito peludo, mas um grande número de campos ( ou seja , schemata altamente esparsa da matriz), pode ser a única maneira de obter o trabalho feito.
fonte
Eu vim uma cruz algo parecido recentemente.
Eu fiz 2 mesas.
Ele é todos os seus objetos. Você definiu o nome dele.
E um tipo desse objeto: - para mim, os tipos disponíveis eram inventário, inventário, item.
E a configuração usual era que n itens são filhos ou inventário, que também é filho do cargo e eu usei uma tabela de junção para juntar objetos uns aos outros
A tabela de configurações contém todos os nomes de campos para esse tipo de objeto específico e o valor em valor.
Exemplo de propriedades do escritório
Localização, telefone, horário de trabalho
E para itens
Etc, todas essas propriedades são impostas pelo modelo e salvas na tabela de configurações como linhas separadas (ainda assim, use replace not insert para evitar várias linhas no mesmo campo)
Então, sempre que eu quero um escritório, carrego-o facilmente com todas as suas relações e configurações em que as configurações object_I'd (objetos solicitados)
Depois disso, giro todas as linhas das configurações e é isso.
E, no caso de eu querer que uma configuração fosse específica para um item de um inventário (não global), defino object_I'd = da tabela de relações object_objects e defino settings.type = relationship_setting
Espero que você entenda o que quero dizer. Tentarei reformatar a resposta quando chegar a um laptop
fonte
Não, não é uma prática ruim. Isso é bastante comum. Em termos de OO, isso é chamado de herança. Você tem um inventário de classe base e duas classes herdadas de AudioCD e móveis.
Você precisa decidir como o item de inventário, o CD de áudio e os móveis são armazenados no banco de dados.
Se a consulta fácil é mais importante para você e o db-space / normalization não importa, você implementaria o esquema "tabela por hierarquia".
Se o espaço / normalização for mais importante para você e as consultas mais complicadas não forem um problema, você implementaria o esquema "tabela por tipo".
Para obter mais detalhes, consulte herança dotnet tabela por tipo vs tabela por hierarquia ou herança de hibernação java .
fonte