Suponha que eu possua 4 tipos de serviços que ofereço (é improvável que eles mudem com frequência):
- Teste
- desenhar
- Programação
- De outros
Suponha que eu tenha de 60 a 80 serviços reais que se enquadram em uma das categorias acima. Por exemplo, 'um serviço' pode ser "Programa de Teste usando a técnica A" e é do tipo "Teste".
Eu quero codificá-los em um banco de dados. Eu vim com algumas opções:
Opção 0:
Use VARCHAR
diretamente para codificar o tipo de serviço diretamente como uma sequência
Opção 1:
Use banco de dados enum
. Mas enum é mau
Opção 2:
use duas tabelas:
service_line_item (id, service_type_id INT, description VARCHAR);
service_type (id, service_type VARCHAR);
Posso até desfrutar de integridade referencial:
ALTER service_line_item
ADD FOREIGN KEY (service_type_id) REFERENCES service_type (id);
Parece bom, sim?
Mas ainda tenho que codificar as coisas e lidar com números inteiros, ou seja, ao preencher a tabela. Ou eu tenho que criar programação elaborada ou construções de banco de dados ao preencher ou lidar com a tabela. Ou seja, JOINs quando lida diretamente com o banco de dados ou cria novas entidades orientadas a objetos no lado da programação e garante que eu as opere corretamente.
Opção 3:
Não use enum
, não use duas tabelas, apenas use uma coluna inteira
service_line_item (
id,
service_type INT, -- use 0, 1, 2, 3 (for service types)
description VARCHAR
);
Isso é como um 'enum falso' que requer mais sobrecarga no lado do código, como, por exemplo, saber disso {2 == 'Programming'}
e lidar com isso adequadamente.
Questão:
Atualmente eu o implementei usando a Opção 2 , guiada sob conceitos
- não use enum (opção 1)
- evite usar um banco de dados como planilha (opção 0)
Mas não posso deixar de sentir que isso me parece um desperdício em termos de programação e sobrecarga cognitiva - tenho que estar ciente de duas tabelas e lidar com duas tabelas, versus uma.
Por um "caminho menos desperdício", estou olhando Option 3
. A TI é mais leve e requer essencialmente as mesmas construções de código para operar (com pequenas modificações, mas complexidade e estrutura são basicamente as mesmas, mas com uma única tabela)
Suponho que, idealmente, nem sempre seja um desperdício, e há bons casos para qualquer uma das opções, mas há uma boa orientação sobre quando alguém deve usar a Opção 2 e quando a Opção 3?
Quando existem apenas dois tipos (binários)
Para adicionar um pouco mais a essa pergunta ... no mesmo local, tenho uma opção binária de serviço "Padrão" ou "Exceção", que pode ser aplicado ao item de linha de serviço. Eu codifiquei isso usando a opção 3 .
Eu escolhi não criar uma nova tabela apenas para manter os valores {"Padrão", "Exceção"}. Portanto, minha coluna contém {0, 1} e o nome da coluna é chamado exception
, e meu código está fazendo uma tradução {0, 1} => {STANDARD, EXCEPTION}
(da qual codifiquei como constantes na linguagem de programação)
Até agora não gostamos dessa maneira ..... (não gostamos da opção 2 nem da opção 3). Eu acho a opção 2 superior a 3, mas com mais sobrecarga, e ainda assim não consigo escapar da codificação das coisas como números inteiros, independentemente da opção usada em 2 e 3.
ORM
Para adicionar algum contexto, depois de ler as respostas - eu apenas comecei a usar um ORM novamente (recentemente), no meu caso, Doutrina 2. Depois de definir o esquema do banco de dados por meio de anotações, eu queria preencher o banco de dados. Como todo o meu conjunto de dados é relativamente pequeno, eu queria tentar usar construções de programação para ver como ele funciona.
Eu primeiro preenchi service_type
s e depois service_line_item
s, pois havia uma lista existente de uma planilha real. Portanto, coisas como 'padrão / exceção' e 'Teste' são todas as strings da planilha e precisam ser codificadas em tipos apropriados antes de armazená-las no DB.
Encontrei esta resposta SO: O que você usa em vez de ENUM na doutrina2? , que sugeriu não usar a construção enum do DB, mas usar um INT
campo e codificar os tipos usando a construção 'const' da linguagem de programação.
Mas, como apontado na pergunta SO acima, posso evitar o uso de números inteiros diretamente e usar construções de linguagem - constantes - uma vez definidas.
Mas ainda assim ... não importa como você o vire, se eu estou começando string
como um tipo, primeiro tenho que convertê-lo para um tipo adequado, mesmo ao usar um ORM.
Então, se diz $str = 'Testing';
, eu ainda preciso ter um bloco em algum lugar que faça algo como:
switch($str):
{
case 'Testing': $type = MyEntity::TESTING; break;
case 'Other': $type = MyEntity::OTHER; break;
}
A coisa boa é que você não está lidando com números inteiros / números mágicos [em vez disso, lidando com quantidades constantes codificadas], mas o ruim é que você não pode extrair automaticamente as coisas dentro e fora do banco de dados sem essa etapa de conversão. conhecimento.
E foi isso que eu quis dizer, em parte, dizendo coisas como "ainda tenho que codificar e lidar com números inteiros". (Concedido, agora, após o comentário de Ocramius, não precisarei lidar diretamente com números inteiros, mas sim com constantes nomeadas e alguma conversão de / para constantes, conforme necessário).