Come vengono tracciati e inizializzati i dati della tabella di ricerca nella progettazione dell'applicazione?

1

Sfondo

In una tipica applicazione Model-View-Controller che utilizza un database per memorizzare il modello, il consenso sembra essere che le tabelle di ricerca sono una decisione di progettazione solida per i tipi enumerati. Sebbene alcuni DBMS supportino tipi ENUM - una soluzione più semplice - le persone citano gli svantaggi come "i dati non vengono trattati come dati" e "le costose modifiche all'elenco dei membri" come motivi per evitare l'alternativa ENUM .

Tuttavia, un vantaggio della soluzione ENUM è che i dati enumerati sono, per definizione, dichiarati prima che l'applicazione inizi l'esecuzione .

Un semplice esempio potrebbe essere un sito di incontri con User se Relationship Status es. La tabella User verrebbe compilata durante l'esecuzione normale dell'applicazione, ma i dati di Relationship Status dovrebbero (credo) essere "pronti all'uso" non appena l'applicazione viene attivata. Anche se gli stati possono essere configurati / aggiunti / rimossi durante il runtime, si potrebbe pensare che il client non debba aggiungere manualmente l'insieme di relazioni enumerate iniziale ogni volta che viene utilizzata una nuova istanza del database.

Come affermato in precedenza, le colonne ENUM raggiungono questo obiettivo, ma non ho trovato alcuna documentazione generica su come le tabelle di ricerca (le migliori pratiche accettate) possono comportarsi allo stesso modo.

Domanda

Le tabelle di ricerca contengono dati come qualsiasi altra riga in un database, ma con l'avvertenza che rappresentano le enumerazioni: costrutti che, nella logica del programma, sono in genere definiti in fase di compilazione anziché in fase di esecuzione. In che modo le applicazioni MVC gestiscono l'inizializzazione e l'utilizzo dei dati della tabella di ricerca, riconciliandoli con i paradigmi di progettazione della funzione di un programma?

Soluzioni tentate

Per illustrare il motivo per cui i paragrafi precedenti rappresentano effettivamente un ostacolo mentale, ecco alcune alternative che ho considerato (cercando ancora di rimanere indipendenti dal sistema) e perché sembrano non essere all'altezza.

  1. L'utente definisce i dati enumerati durante l'esecuzione

    Per quanto mi riguarda, questa non è una soluzione valida, perché i dati elencati spesso svolgono un ruolo nella logica dell'applicazione. Ad esempio, un sistema di contabilità a partita doppia può avere credit e debit account e le transazioni per tali account devono essere confrontate e riconciliate in modo diverso a seconda di quali tipi di account sono in uso. Anche se un client è autorizzato a creare altri tipi di account, dovrebbe essere previsto che sappia che credit / debit deve essere aggiunto prima che l'applicazione sia addirittura funzionante?

  2. Includi istruzioni di inserimento dei dati nella definizione dello schema del database

    Questa opzione sembra molto più ragionevole, e il mio istinto mi dice che questa soluzione è corretta, ma la mia inesperienza mi impedisce di legare insieme le estremità. La chiamata allo script di creazione dello schema si verifica in genere in alcuni processi di distribuzione prima dell'esecuzione dell'applicazione, ma qual è la procedura se sono necessari aggiornamenti ai valori della tabella di ricerca? Inoltre, l'applicazione nel suo complesso dovrebbe seguire il principio DRY, ma (riferendosi all'esempio precedente) se la logica dell'applicazione dipende dalla conoscenza dei tipi di account credit / debit , come deve il codice "sapere" che dati senza una definizione ridondante nella fonte?

Per inciso, ho sempre lavorato con due ORM nella mia storia di ingegnere del software: SQLAlchemy , e un strumento di acquisto utilizzato da un datore di lavoro per generare dinamicamente codice appropriato per classi di modelli in Java. In ogni caso, voglio che questa domanda sia indipendente dal sistema, ma forse questo sfondo può aiutare i lettori a lottare per capire i miei ostacoli mentali su questo problema.

    
posta RNanoware 04.07.2017 - 19:01
fonte

2 risposte

0

Include data insertion statements in the database schema definition

Questo è l'approccio migliore. Il mio team usava usare i tipi di enum di database, e dopo aver provato dolore ad aggiungere o modificare valori nel tipo di enum, decidemmo di passare a LUT. Il nostro approccio era di definirli nella definizione dello schema e ha funzionato molto bene. Consentire al LUT di cambiare in fase di esecuzione non è una buona idea se viene modellato da un codice enumerato. Abbiamo aggiunto un vincolo di controllo per impedire che dati errati entrino nella LUT.

what is the procedure if updates to the lookup table values are necessary?

In sostanza si aggiornano i valori nella LUT nello stesso modo in cui si aggiornerebbe lo schema nel database. Abbiamo script di migrazione del database che vengono eseguiti da Flyway ogni volta che viene avviata la nostra applicazione.

how is the code supposed to "know about" that data without a redundant definition in the source?

Questo è un po 'più complicato ma realizzabile. Nella mia organizzazione abbiamo appena deciso di ripetere le definizioni nelle nostre migrazioni e nel codice (le nostre enumerazioni non erano molto lunghe). Per evitare ciò, è possibile utilizzare le migrazioni di database basate su codice (anche Flyway le supporta) per aggiornare il proprio LUT utilizzando i valori di un codice enumerato. In Java dovresti usare il metodo values() per accedere a tutti i membri dell'enum e inserirli nella LUT.

Il processo sarebbe simile a questo:

migration sql v1: define the LUT schema
migration code v2: drop all LUT rows and insert values from code enum into LUT

Se poi modifichi l'enum nel codice e hai bisogno di aggiornare il tuo LUT:

migration code v3: drop all LUT rows and insert values from code enum into LUT
    
risposta data 04.07.2017 - 22:05
fonte
-1

Penso che la ragione del tuo blocco mentale su questo sia che le tabelle di ricerca non rappresentano enumerazioni e non dovrebbero essere usate per tali.

diciamo che abbiamo un c # enum nel nostro codice, che è davvero una fantasia int sotto. Lo usiamo per rappresentare possibili stati dell'oggetto Door

1 = open
2 = closed
3 = ajar

Ora manteniamo l'oggetto Door su una tabella di database

id = 1
state = "open"

Lavoro fatto. quando leggiamo i dati fuori dal tavolo possiamo rielaborare la stringa di stato in un enum. Se aggiungiamo più valori all'enumerazione, possono essere serializzati su e da stringhe senza problemi.

Ma decidiamo di aggiungere una tabella di ricerca che rispecchi l'enum

doorStates
id= 1
name = "open"

door
id = 1
state = 1

Possiamo interrogare i dati con un join e analizzare la stringa di stato, o analizzare lo stato int dalla porta a un enum. Salviamo anche spazio su disco se abbiamo più porte che stati.

Ma! abbiamo introdotto un artefatto pericoloso nel nostro sistema.

Se aggiungiamo un nuovo valore all'enum, dobbiamo assicurarci che la tabella di ricerca corrisponda a

Se l'id è sincronizzato con il valore enum int dobbiamo stare attenti a non usarlo

Abbiamo perso significato nel tavolo della porta. lo stato 1 non ha significato senza la ricerca

C'è una tendenza a smettere di fare riferimento alla tabella di ricerca ed equiparare l'id allo stato. Le persone chiederanno un rapporto di tutte le porte nello stato 2 anche se nel nostro codice stato Id non viene mai usato.

Se il tuo codice esegue sempre query door join doorState e omette la colonna ID stato. Quale sarà. L'unico vero effetto del cambiamento è quello di risparmiare spazio sul disco.

Se hai una relazione 1 a 1 con un oggetto figlio, usa una tabella di ricerca. Se hai un enum, salvalo come una stringa.

    
risposta data 05.07.2017 - 00:40
fonte

Leggi altre domande sui tag