Melhor maneira de referenciar dados estáticos do banco de dados no código?

24

Muitos aplicativos incluem 'dados estáticos': dados que realmente não são alterados durante a vida útil do aplicativo. Por exemplo, você pode ter uma lista de áreas de vendas que provavelmente será uma lista fixa no futuro próximo.

Não é incomum encontrar esses dados estáticos em uma tabela de banco de dados (geralmente porque você deseja consultá-los nas chaves estrangeiras de outras tabelas). Uma tabela de exemplo simples terá um ID para usar como chave primária e uma Descrição. Por exemplo, sua tabela SalesArea terá (pelo menos) uma coluna SalesAreaId e uma coluna SalesAreaDescription.

Agora, no código, você pode não querer tratar cada linha da tabela da mesma forma. Por exemplo, você pode definir uma Área de vendas padrão em algumas telas, fornecer números diferentes para algumas áreas ou restringir o que os usuários podem fazer em outras áreas.

Qual é a melhor maneira de se referir a esses dados estáticos no código? Por quê?

  1. Codifique as descrições no seu código. Use isso para procurar o SalesAreaId no banco de dados quando você precisar.
  2. Codifique os IDs no seu código. Use isso para procurar o SalesAreaDescription quando você precisar.
  3. Adicione uma coluna à tabela para cada finalidade, por exemplo, uma coluna "IsDefaultOnProductLaunchScreen" e assim por diante (pode haver muitas).
  4. Algo mais.

Há outras considerações especiais que devo fazer ao lidar com dados estáticos do banco de dados? Por exemplo, dando um nome especial a essas tabelas?

Kramii Restabelecer Monica
fonte
11
Duplicado possível: programmers.stackexchange.com/questions/304169/... Acredito que as respostas em que um (ligado) chega ao coração do problema um pouco melhor IMO
JoeCool

Respostas:

14

Que tal carregá-los em um cache (geralmente implementado como uma tabela de hash) quando o aplicativo é iniciado? Se você fizer isso, nem precisará consultar o banco de dados (bem, não mais de uma vez).

Eu também sugeriria evitar qualquer código embutido. Adicione indicadores padrão (inicialmente na tabela DB e também na estrutura do cache) para telas que precisam de padrões. Para fazer pesquisas em não-defauilts, tente armazenar as chaves que serão pesquisadas em um arquivo de configuração ou propriedades, se puder.

FrustratedWithFormsDesigner
fonte
O armazenamento em cache é bom, é claro, mas como você atualiza esses valores? Presumivelmente, uma reinicialização de aplicativo ou algum tipo de estratégia de invalidação de cache?
1611 Steve
11
@ Steve Sim, exatamente. Depende do aplicativo. Reiniciar é bom para algo que começa com freqüência. Para um aplicativo de execução demorada, talvez recarregue o cache uma vez por dia em períodos lentos. Minha pergunta seria: que tal um cenário em que o aplicativo execute muitos tempos de vida muito curtos. Talvez um script PHP ou algo semelhante.
tylermac
O banco de dados será executado seu próprio cache de dados acessados com freqüência para que você irá re-implementação de algo que já está implementado (e provavelmente não tão bem!)
James Anderson
@JamesAnderson: Caching nos meios de aplicação não só irá sempre ser uma chamada para o banco de dados. Sim, os bancos de dados terão seus próprios caches, mas eles poderão ser invalidados / atualizados por eventos fora do controle do seu aplicativo, e você ainda precisará ter uma conexão com o banco de dados e fazer uma consulta para obter esses dados (e espero que eles estejam no diretório cache do banco de dados). Realmente não é tão difícil implementar um cache no aplicativo simples.
FrustratedWithFormsDesigner
7

Uma alternativa ao banco de dados ou à codificação rígida é usar um arquivo de configuração lido no momento da inicialização. Você pode armazenar esses dados em uma estrutura somente leitura dentro do seu código.

No caso raro (mas não impossível) em que você edita esses dados, será necessário reiniciar o aplicativo. Se isso não for possível, você pode escrever um gerenciador de configuração mais complexo que verifique alterações no arquivo de configuração toda vez que os dados forem acessados, isso é realmente bastante eficiente, pois você só precisa verificar um carimbo de data / hora no arquivo e invalidar todos os dados se o arquivo for atualizado.

Steve
fonte
11
Boa ideia para alguns tipos de dados estáticos, mas não tão bons se você deseja aplicar os relacionamentos FK, conforme descrito na pergunta.
Kramii Restabelece Monica
A pergunta não dizia que isso era um requisito, apenas um cenário. Se não for necessário, a abordagem do arquivo de configuração funcionará bem.
14111 Steve
Você está certo, eu não era clara o suficiente. Mas estou satisfeito ... porque aprendi algo com sua resposta. Eu nunca me deparei com essa abordagem antes.
Kramii Restabelecer Monica
3

Se os dados estiverem relacionados aos dados existentes no seu banco de dados, provavelmente é tão eficiente adicioná-lo ao banco de dados quanto ao código. Se isso não acontecer, geralmente sou tentado a "aceitar esse item uma vez" e colocá-lo em código até a primeira vez que ele muda.

Freqüentemente, o que pensamos ser estático acaba não sendo, e quando isso acontece, você não precisa esperar pelo lançamento do código para que uma alteração seja aprovada. Assim que isso acontecer uma vez, coloque-o no banco de dados e escreva uma página de administrador para fazer mais atualizações.

Para dar o seu exemplo, se você já possui Áreas de Vendas no banco de dados, adicione uma descrição lá, não crie uma tabela de hash para relacionar os dados do banco de dados a listas codificadas. Mas se você não criar uma tabela de hash de áreas de vendas por todos os meios, mas esteja pronto, na primeira vez que alguém alterar uma descrição ou adicionar uma nova área de vendas, mova-a para o banco de dados.

pdr
fonte
"Frequentemente, o que pensamos ser estático acaba não sendo" - é verdade.
Kramii Restabelece Monica
3

Por que não apenas codificar tudo? O principal problema que sempre tive foi referenciar valores estáticos do banco de dados no código do aplicativo. Uma coisa é se você está criando diretamente uma lista suspensa ou algo fora dos valores estáticos, mas e se alguma lógica do aplicativo depender dos valores do banco de dados?

No momento, em um aplicativo simples, tenho uma lista de estados de edição de partes do conteúdo: Rascunho, Publicado, Arquivado.

Os itens de conteúdo precisam ser tratados de maneira diferente, dependendo do estado em que estão. Se eu mantivesse esses dados de estado no banco de dados, com os valores 1, 2, 3, respectivamente, como proceder para verificar se há algo em Rascunho Estado?

if (content.State == 1)
ou
if (content.State == "Draft")?

Eu apenas codifiquei os valores!
O mesmo se você usar uma tabela de cache / hash: você ainda precisará usar algum valor escrito em seu código como uma chave para procurar seus dados.

Quais são as desvantagens da abordagem codificada?

Dave
fonte
A desvantagem é como disse pdr: "Muitas vezes, o que pensamos ser estático acaba por não ser".
precisa saber é o seguinte
2
Mas se você estiver realmente fazendo referência aos valores de dados estáticos no código, não poderá alterá-los no banco de dados sem interromper o aplicativo. Com certeza, depende do motivo pelo qual os dados estão sendo usados: como mencionei acima, se estiver apenas preenchendo um elemento da interface do usuário para que um usuário possa selecionar um valor e fazer com que esse seja direcionado diretamente de volta ao banco de dados como parte de um registro em outra tabela , os dados estáticos no banco de dados podem mudar independentemente do código do aplicativo. Tenho certeza de que é a situação da @pdr: o aplicativo que manipula o conjunto de dados estáticos como um único item.
Dave
2

Semelhante ao que o FrustratedWithFormsDesigner disse, isso geralmente é feito com um cache, pois significa que você só precisa carregar os dados estáticos uma vez, mas segue o padrão OAOO, o que significa que não estamos definindo os dados em dois lugares (banco de dados e seu código).

Eu sei que o NHibernate ORM oferece essa funcionalidade através de um cache de segundo nível . Você pode dizer para armazenar dados em cache de uma determinada tabela e dizer que é somente leitura. Ele será carregado na primeira vez que for necessário e não atingirá o banco de dados novamente depois disso, mesmo se você acessar os dados de várias sessões.

Scott Whitlock
fonte
+1 para uma vez e apenas uma vez. Mas e quanto a tratar diferentes linhas de maneira diferente?
Kramii Restabelece Monica
11
@ Kramii - Você pode usar algo como classes de enumeração . Se os metadados estiverem relacionados apenas ao seu programa, eu colocaria a lógica de negócios ( IsDefaultOn...) em uma propriedade na entidade. Faça com que ele retorne verdadeiro para a única entidade. Isso permitiria encontrar essa entidade, considerando toda a coleção. Ou você pode usar uma classe de controlador que fornecerá a entidade apropriada uma chamada de método.
Scott Whitlock
2

Esta é a otimização prematura no seu pior.

Em primeiro lugar, qualquer DBMS moderno recuperará dados de pequenas tabelas na velocidade da luz e todos eles têm algoritmos de cache que variam de bom a excelente (quanto mais você paga pelo DBMS, melhor o cache!). Então você está otimizando algo que consome recursos mínimos.

Em segundo lugar, você tem muito pouca experiência com aplicativos de negócios do mundo real, se imaginar que algo como uma "área de vendas" são dados estáticos. Eles podem sofrer alterações a cada mudança do Diretor de Marketing ou CEO. Então você está caminhando para um mundo de dor daqui a dois anos.

Existem apenas duas maneiras de ir aqui: -

Armazene-o em um banco de dados e acesse os dados com sql "normal".

Armazene-o em um arquivo de configuração XML sofisticado (possivelmente acessado via REST ou SOAP), que pode ser facilmente editado sempre que houver "uma mudança estratégica de política".

James Anderson
fonte
1

Depende do que você está fazendo com os dados. Se for uma lista de algo, geralmente o puxarei para uma matriz. Se a lista precisar crescer em outra versão, é fácil adicionar no banco de dados e alterar o código para manipular os dados extras na matriz (o que pode nem ser necessário, dependendo do código, por exemplo, listar os dados com um loop for usando o limite superior da matriz). Se for uma lista de configurações, normalmente codificarei essas como normalmente não existem muitas e é mais fácil e rápido do que usar uma instrução SQL. Se for uma configuração que o usuário possa alterar e eu desejar salvar a seleção para lançamentos subsequentes, criarei uma tabela para usar como um registro e apenas puxarei entradas individuais para as variáveis, conforme necessário.

MaQleod
fonte
1

Sei que essa resposta foi aceita, mas queria compartilhar como fizemos isso em minha última loja de desenvolvimento da Web, onde tentamos reduzir ao máximo possível as E / S de banco de dados.

Usamos arquivos de inclusão do servidor para o maior número possível de estruturas de dados do tipo pesquisa. Principalmente para navegação no site (para incluir subnavegação), mas também a usamos para o maior número possível de caixas suspensas e caixas de seleção (Estados, países, categorias).

Originalmente, extraímos todos esses dados do banco de dados. Como fornecemos ao cliente um widget de administrador, eles poderiam alterar esses dados à vontade e nunca ficamos atolados com pequenas mudanças de moeda de dez centavos. Na maioria das vezes, esses dados quase nunca mudavam, mas ocasionalmente mudavam.

Estávamos sempre procurando tempos de carregamento mais rápidos. Decidimos implementar o máximo de arquivos de texto estáticos do lado do servidor. Fizemos isso ao lado do widget de administração. Cada vez que uma tabela do banco de dados era atualizada, regenerávamos o arquivo de texto estático correspondente. Isso nos deu um ambiente muito flexível e rápido.

Michael Riley - também conhecido por Gunny
fonte
0

Minha solução para isso, que pode não funcionar em todas as situações, é vincular os dados estáticos do banco de dados a um código embutido enum. Como o problema vem do fato de ter dados dinâmicos (banco de dados) vinculados à lógica estática (código), torne essa ligação explícita (e perdida) tendo uma tabela de banco de dados que se associa ao enum. Ex:

LooseDBCodeBinding (database table)
   ID : Int32 (key)
   Name : String
   HardCodedTypeID : Int32

// in code:
public enum LooseDBCodeBinding
{
   TYPE_1 = 1,
   TYPE_2 = 2,
   TYPE_3 = 3 // etc...
}

Em seguida, escreva uma interface do usuário que permita visualizar facilmente a lista de LooseDBCodeBindingregistros e mapeá-los para LooseDBCodeBinding enumvalores (incluindo o suporte a ligações "quebradas"). Em seguida, você pode programar em torno do enum, e projetar o banco de dados em torno da chave da tabela, e é apenas essa tabela que tem conhecimento dos dois contextos.

Dave Cousineau
fonte