Domanda

Ho un problema difficile che ho pasticciare con per qualche giorno ora e cant trovare una soluzione ottimale per.

Queste sono le mie tabelle:

  • sito
  • site_node
  • pagina

La tabella nodo del sito contiene una lista di nodi che rappresentano una gerarchia (utilizzando set nidificato). Ogni nodo deve avere una o più pagine associate. Ogni sito deve avere una pagina di errore associato e una pagina non trovata.

Quindi, una pagina deve o appartenere a un nodo, o un sito come un errore o non trovato pagina. Le soluzioni Attualmente sto giocando con sono:

  1. ParentType e ParentID campi della tabella delle pagine, dove tipo sarebbe essere sia "nodo", "site_error" o "site_notFound" e l'id sarebbe il sito o ID nodo (a seconda di quale è rilevante per il tipo).
  2. campo nodeId sul tavolo pagina che può essere nullo, e poi campi errorPageId e notFoundPageId sul tavolo sito.

Opzione 1 assicura che ogni pagina appartiene ad uno ed un solo altro soggetto, anche se il rapporto sopraelevazione effettivamente essere applicata come campo parentId può puntare a più di un luogo.

opzione # 2 è più pulito, ma è fondamentalmente dicendo che il sito "appartiene" alle pagine due di errore e che non si trovano, e che probabilmente è cattiva pratica.

Ogni pensiero o suggerimenti?
Grazie,
Jack

È stato utile?

Soluzione

  

Opzione # 1 assicura che ogni pagina   appartiene ad uno ed un solo altro   entità, anche se il rapporto sopraelevazione   diventi esecutivo come parentId   campo può puntare a più di un   posto.

destro. In termini di teoria relazionale, il problema è che la vostra colonna "parentId" viola terzo normale modulo , perché il suo significato varia per riga, in base al valore in parentType (una colonna non chiave).

Non avresti un database progettato correttamente se una singola colonna poteva contiene il numero di telefono di qualcuno o la loro data di nascita, per riga, a seconda qualche altra bandiera. Questi sono due fatti diversi circa la persona, e ciascuno di loro meritano la loro propria colonna. Analogamente, la memorizzazione sia site_id o id_nodo in una singola colonna avrebbe lo stesso problema.

Un altro indizio che questo è un disegno difettoso è che non è possibile dichiarare un vincolo di chiave esterna per puntare a o di due tabelle di riferimento.

  

opzione # 2 è più pulito, ma è   fondamentalmente dicendo che il sito   "Appartiene" ai due errore e non   trovato le pagine, e questo è probabilmente male   pratica.

Capisco perché stai dicendo che, a causa del appartiene a convenzioni nei quadri Rails-like. Ma queste sono le convenzioni; essi non sono necessariamente l'unica relazione che le chiavi esterne possono modellare. È possibile effettuare un'entità si riferisce esattamente ad un altro soggetto, in un ha una rapporto. In questo caso, la chiave esterna inverte la direzione.

Vorrei dire che è logicamente vero che la pagina di errore e la pagina non trovata appartengono a il sito, non il contrario. E il modo per renderle obbligatorie è quello di avere un altro soggetto di riferimento queste pagine, e applicare il vincolo NOT NULL a questi riferimenti. Questo è quello che hai descritto.

CREATE TABLE site (
  . . .
  error_page_id     INT NOT NULL,
  notfound_page_id  INT NOT NULL,
  FOREIGN KEY (error_page_id)    REFERENCES pages (page_id),
  FOREIGN KEY (notfound_page_id) REFERENCES pages (page_id)
);

Questa incontra il vostro bisogno immediato, è applicabile, ed è in forma normale.


suggerisce fare nodi fittizi per errore e non si trova pagine. Anche se questo permette a questi nodi di essere memorizzati nella gerarchia del nodo, non riesce a far valere che un sito deve avere queste pagine. Cioè, un sito potrebbe essere memorizzato senza i riferimenti a questi nodi.

@Tony Andrews suggerisce memorizzando due colonne in ogni pagina, site_id e site_node_id, e l'aggiunta di un vincolo CHECK per garantire che esattamente uno di questi è non NULL. Questo sembra meglio che l'opzione parent_id / parent_type, ma ancora non offre alcuna applicazione che ogni sito deve avere un errore e una pagina non trovata.

Altri suggerimenti

Fai nodi sito fittizi per l'errore o non trovato pagina. È possibile contrassegnare come uno specifico tipo di nodo secondo la vostra prima opzione. In questo modo sarà più facile fare un meccanismo gestore generico. Si farà anche si unisce più semplice che contribuirà con le prestazioni delle query del database. Inoltre, consente di aggiungere più tipi di pagine 'speciali' (forse un finestra di accesso) o fare questo configurabile senza dover modificare lo schema del database.

Un'altra opzione è quella di avere 2 colonne site_id e site_node_id in questo modo:

create table pages
 ( page_id ... primary key
 , site_id references sites
 , site_node_id references site_nodes
 , ...
 , constraint site_or_node check (  site_id is null and site_node_id is not null
                                 or site_id is not null and site_node_id is null
                                 )
 );

Ora è possibile utilizzare l'integrità referenziale per garantire che ogni pagina appartiene a un sito o di un nodo, e non entrambi.

L'opzione 2 ha molto più senso e salverà il tuo cervello in seguito su tutta la linea, se e quando più complicazioni nascono. La relazione uno-a-uno dei sito all'errore / notfound pagina lo rende perfetto per un vincolo di chiave esterna.

Una modifica di Opzione 1.

Includere due colonne separate, ParentNodeID e ParentSiteID. Lasciare una di queste due colonne NULL, a seconda dei casi. Ora si può ancora dichiarare un vincolo di chiave esterna (riferimenti) per ogni chiave esterna.

Non capisco davvero il caso SiteNotFound. Potrebbe lasciare entrambe le chiavi esterne NULL in questo caso?

Il tuo unisce e ricerche sarà più semplice. Sarà inoltre intende mantenere 1NF. Questa non è una coincidenza.

L'opzione 1 combina i valori provenienti da diversi domini in un unico campo. Ciò è disegno male sul campo e IIRC viola 1NF.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top