Supponiamo che io abbia 4 tipi di servizi che offro (è improbabile che cambino spesso):
- analisi
- Design
- Programmazione
- Altro
Supponiamo che io abbia 60-80 di servizi effettivi che rientrano ciascuno in una delle categorie precedenti. Ad esempio, "un servizio" può essere "Programma di test utilizzando la tecnica A" ed è di tipo "Test".
Voglio codificarli in un database. Ho trovato alcune opzioni:
Opzione 0:
Utilizzare VARCHAR
direttamente per codificare il tipo di servizio direttamente come stringa
Opzione 1:
Usa il database enum
. Ma l' enum è malvagio
Opzione 2:
usa due tabelle:
service_line_item (id, service_type_id INT, description VARCHAR);
service_type (id, service_type VARCHAR);
Posso anche godere dell'integrità referenziale:
ALTER service_line_item
ADD FOREIGN KEY (service_type_id) REFERENCES service_type (id);
Suona bene, sì?
Ma devo ancora codificare le cose e gestire i numeri interi, vale a dire quando si popola la tabella. Oppure devo creare elaborati programmi o costrutti DB durante il popolamento o la gestione della tabella. Vale a dire, JOINs quando si ha a che fare direttamente con il database o quando si creano nuove entità orientate agli oggetti sul lato della programmazione e si assicura che le funzioni correttamente.
Opzione 3:
Non usare enum
, non usare due tabelle, ma usa solo una colonna intera
service_line_item (
id,
service_type INT, -- use 0, 1, 2, 3 (for service types)
description VARCHAR
);
Questo è come un "falso enum" che richiede un maggior sovraccarico sul lato del codice delle cose, come ad esempio conoscerlo {2 == 'Programming'}
e affrontarlo in modo appropriato.
Domanda:
Attualmente l'ho implementato usando l' opzione 2 , guidata sotto concetti
- non usare enum (opzione 1)
- evitare di utilizzare un database come foglio di calcolo (opzione 0)
Ma non posso fare a meno di sentirmi dispendioso in termini di programmazione e sovraccarico cognitivo: devo essere consapevole di due tabelle e occuparmi di due tabelle, anziché una.
Per un "modo meno dispendioso", sto guardando Option 3
. L'IT è più leggero e richiede essenzialmente gli stessi costrutti di codice per funzionare (con lievi modifiche ma la complessità e la struttura sono sostanzialmente le stesse ma con una sola tabella)
Suppongo che idealmente non sia sempre dispendioso, e ci sono buoni casi per entrambe le opzioni, ma c'è una buona linea guida su quando si dovrebbe usare l'opzione 2 e quando l'opzione 3?
Quando ci sono solo due tipi (binari)
Per aggiungere un po 'di più a questa domanda ... nella stessa sede, ho un'opzione binaria di servizio "Standard" o "Eccezione", che può essere applicata all'elemento pubblicitario del servizio. L'ho codificato usando l' opzione 3 .
Ho scelto di non creare una nuova tabella solo per contenere i valori {"Standard", "Eccezione"}. Quindi la mia colonna contiene solo {0, 1} e il mio nome di colonna viene chiamato exception
, e il mio codice sta facendo una traduzione {0, 1} => {STANDARD, EXCEPTION}
(che ho codificato come costanti nel linguaggio di programmazione)
Finora non mi piaceva così ..... (non gradire l'opzione 2 né l'opzione 3). Trovo l'opzione 2 superiore a 3, ma con un overhead maggiore, e tuttavia non riesco a sfuggire alla codifica delle cose come numeri interi, indipendentemente dall'opzione che utilizzo tra 2 e 3.
ORM
Per aggiungere un po 'di contesto, dopo aver letto le risposte - ho appena iniziato a utilizzare di nuovo un ORM (di recente), nel mio caso Doctrine 2. Dopo aver definito lo schema DB tramite Annotazioni, volevo popolare il database. Poiché il mio intero set di dati è relativamente piccolo, volevo provare a usare costrutti di programmazione per vedere come funziona.
Ho prima popolato service_type
s, e poi service_line_item
s, poiché esisteva un elenco esistente da un foglio di calcolo effettivo. Quindi cose come "standard / exception" e "Testing" sono tutte stringhe sul foglio di calcolo e devono essere codificate in tipi appropriati prima di memorizzarle nel DB.
Ho trovato questa risposta SO: che cosa usi invece di ENUM in doctrine2? , che suggeriva di non usare il costrutto enum di DB, ma di usare un INT
campo e codificare i tipi usando il costrutto "const" del linguaggio di programmazione.
Ma come sottolineato nella precedente domanda SO, posso evitare di usare direttamente numeri interi e usare costrutti di linguaggio - costanti - una volta definiti ...
Ma comunque ... non importa come lo giri, se inizio con string
un tipo, devo prima convertirlo in un tipo corretto, anche quando utilizzo un ORM.
Quindi, se dico $str = 'Testing';
, ho ancora bisogno di avere un blocco da qualche parte che fa qualcosa di simile:
switch($str):
{
case 'Testing': $type = MyEntity::TESTING; break;
case 'Other': $type = MyEntity::OTHER; break;
}
La cosa buona è che non hai a che fare con numeri interi / magici [invece, con quantità costanti codificate], ma la cosa brutta è che non puoi estrarre e rimuovere automaticamente le cose dal database senza questo passaggio di conversione, nel mio conoscenza.
E questo è ciò che intendevo, in parte, dicendo cose come "devono ancora codificare le cose e gestire gli interi". (Concesso, ora, dopo il commento di Ocramius, non dovrò occuparmi direttamente degli interi, ma delle costanti nominate e della conversione da / verso costanti, se necessario).