Perché le dipendenze sono tipicamente invertite quando si rappresentano oggetti complessi come tabelle relazionali?

5

Sto attraversando una sorta di fase in cui analizzo in modo eccessivo e in secondo luogo indovina ogni singola decisione che prendo quando tento di scrivere software che mi impedisca di ottenere qualcosa.

Recentemente ho riscontrato la necessità di archiviare un oggetto C # "complesso" in un database SQLite. Per riassumere l'oggetto in un esempio minimo, diciamo solo che questo oggetto, di tipo Nodo, ha una lista di figli di tipo Foglia. Mentre si definiscono le lezioni, la maggior parte sarebbe d'accordo sul fatto che è buona norma tenere qualsiasi riferimento a Node su Leaf, questo permette a Leaf di essere indipendente, riutilizzabile e avere un "unico scopo".

public class Node
{
    public string Name { get; set; }
    public List<Leaf> Leaves { get; set;}
}

public class Leaf
{
    public string Name { get; set; }
    public int SomeValue { get; set; }
}

Ora, quando si scrivono le definizioni della tabella SQL, pre-fusione di plast1k farebbe qualcosa del genere (e presumo che anche il resto del mondo):

Nodes
-ID (int, identity)
-Name (varchar)

Leaves
-ID (int, identity)
-Name (varchar)
-SomeValue (int)
-NodeID (int, foreign key)
-Index (int)

Ma ora abbiamo creato una dipendenza tra Leaf e Nodes. Se guardi attentamente abbiamo anche creato una dipendenza tra Leaf e List < & gt ;. Più ci penso (fermati qui se questo è in effetti l'unico problema) più non mi piace.

Ho un'esperienza di progettazione di database pratica limitata. Il mio istinto è stato quello di iniziare a delineare la relazione, che in seguito ho imparato è chiamata bridge / linking table, e sembra essere una pratica standard quando la relazione è molti a molti.

Leaves
-ID (int, identity)
-Name (varchar)
-SomeValue (int)

LeavesMapping
-LeafID
-NodeID
-Index

All'inizio sembrava che andasse bene, ma ha iniziato a diventare difficile da gestire con i dati reali della mia vita. Ho anche deciso di ottimizzarlo per riordinare gli elementi dell'elenco e lo sto modellando nel database come un elenco collegato (usando NextLeaf piuttosto che un indice, per esempio).

Questo è davvero il modo giusto per farlo? Ci sono alternative? Quali costrutti mancano a modelli di dati relazionali che ci costringono a fare questo? Ci sono database che possono modellare questo allo stesso modo del codice?

    
posta plast1k 08.10.2016 - 05:01
fonte

2 risposte

3

Smetti di trattare il tuo database relazionale come un archivio di oggetti.

In pratica, sembra che tu abbia degli oggetti che stai serializzando in un database SQL. Un database SQL crea una posizione di awkard per archiviare gli oggetti a causa del disadattamento dell'impedenza della relazione tra oggetti . OO e le entità di visualizzazione relazionale in modo diverso, e troverai molti casi che mappano goffamente tra di loro in aggiunta a quelli che hai già osservato. Di conseguenza, i tuoi attuali usi rendono il paradigma relazionale simile a un cattivo archivio di oggetti.

Una possibilità è rinunciare a provare a utilizzare un database SQL. Utilizzare invece un database di archivio di documenti che archivia naturalmente gli oggetti. Prendiamo ad esempio un database NoSQL che memorizza oggetti JSON. Troverai molto naturale serializzare i tuoi oggetti su JSON e memorizzarli. A seconda della lingua scelta, esistono diversi progetti in grado di adempiere a questo ruolo.

Un'altra possibilità è usare SQL, e basta gestire l'impedenza. Non cercare di forzare le tue tabelle SQL per associare 1: 1 ai tuoi oggetti, sarà solo doloroso. Dovresti accettare che la tua tabella Leaf sia a conoscenza della tabella dei nodi e che il tuo codice responsabile per le query debba solo occuparsene.

Oppure, puoi andare intero e abbracciare il paradigma relazionale. Non iniziare con oggetti e serializzarli in un database SQL. Inizia con le tabelle SQL e visualizza tutti gli oggetti come derivati da essi. Invece di pensare a un nodo che contiene un elenco di foglie, dovresti pensare alle entità del nodo e alle entità foglia che hanno una relazione uno-a-molti che modellate di conseguenza.

Il paradigma relazionale è davvero potente quando si dispone di un complesso insieme di arrangiamenti tra diverse entità. Ma quando stai serializzando i tuoi oggetti, non ti dà molto. Non è tanto il paradigma relazionale che manca di funzionalità, ma richiede che tu pensi in modo diverso al tuo problema e metti innanzitutto la relazione tra le entità e non pensi a tutte le relazioni come a una composizione.

    
risposta data 08.10.2016 - 06:23
fonte
6

Non dovresti applicare i principi di progettazione OOP a come rappresenti i dati in un database relazionale (SQL). I principi di progettazione OOP riguardano il comportamento e le interazioni tra gli oggetti, le interfacce e l'incapsulamento. Nulla di tutto ciò è importante nel database, che riguarda solo dati e coerenza.

Dal punto di vista del database, c'è una relazione uno-a-molti tra nodi e foglie che significa che il tuo primo disegno è corretto. Ma come queste relazioni sono rappresentate nell'applicazione a livello di oggetto (che tipo di raccolta, quali direzioni di navigazione sono possibili e così via) non è di alcuna preoccupazione per il database.

È naturale pensare alle righe di una tabella in un database come corrispondenti agli oggetti, ma l'analogia si rompe se la si spinge fino a lontano. Una riga non rappresenta un oggetto, ma è un'affermazione su una relazione tra i dati. Ad esempio la tabella Leaves ha una chiave esterna a Nodes - questo non dice che una foglia "ha un" nodo in senso OO o che una foglia "conosce" questo nodo o viceversa. Dichiara solo che esiste un nodo per ogni foglia, che può essere rappresentato in vari modi in un modello OO.

Da uno sfondo di sviluppo di applicazioni, potrebbe sembrare che i database relazionali siano solo un modo ingombrante per "persistere" sugli oggetti. Ma dal punto di vista di un database relazionale i dati stessi sono la cosa importante e le applicazioni sono solo una "interfaccia utente" personalizzata che consente di manipolare i dati. I database relazionali sono progettati per consentire a più applicazioni indipendenti di interagire con i dati, pertanto la progettazione dello schema non deve dipendere dai dettagli di implementazione su alcuna particolare applicazione. Altre applicazioni potrebbero non essere nemmeno programmi OO, ma potrebbe essere un programma funzionale o forse un utente che scrive query ad-hoc.

Lo schema del database dovrebbe garantire che nessuna applicazione possa rendere i dati incoerenti. Preferibilmente rendendolo impossibile per rappresentare i dati non validi nello schema. Il tuo secondo progetto con una tabella LeavesMapping è pericoloso poiché consentirebbe a qualcuno di consentire a una foglia di essere associata a due nodi. Questo semplicemente non è possibile nel primo progetto, che quindi rappresenta meglio i vincoli intrinseci del modello di dati.

Come per Index contro NextLeaf , entrambi gli approcci hanno il problema di considerare l'ordine come una proprietà intrinseca senza alcuna semantica. Dovresti prima chiarire che cosa è la semantica dell'ordine. Ad esempio, un albero di directory non ha ordinamento intrinseco, ma potrebbe essere visualizzato utilizzando un ordinamento selezionato nell'interfaccia utente, in base a proprietà intrinseche come nome, data di creazione e così via. Quindi memorizzerai queste proprietà ma non ordini specifici. Se si tratta di un albero genealogico, i fratelli vengono ordinati per convenzione in base ai dati di nascita, quindi ancora una volta non è necessario un campo separato per l'ordine.

    
risposta data 08.10.2016 - 11:10
fonte

Leggi altre domande sui tag