Come evitare una dipendenza ciclica (riferimento circolare) tra 3 tabelle?


10

Ho 3 tavoli:

  • Persone
  • Inviare
  • Piace

Quando progetto il modello ER ha una dipendenza ciclica:

         1: N
Persone -------- <Posta

         1: N
Posta ---------- <Mi piace

         1: N
Persone -------- <Mi piace

La logica è:

  • 1 persona può avere molti post.

  • 1 post ha molti Mi piace.

  • 1 persona può apprezzare molti post (la persona creata non può apprezzare il proprio post).

Come posso rimuovere questo tipo di design ciclico? O il mio design db è sbagliato?

Risposte:


10

Regole di business

Facciamo alcune riformulazioni alle regole aziendali che hai presentato:

  • A Personcrea zero-uno-uno-molti Posts .
  • A Postriceve zero-uno-uno-molti Likes .
  • A si Personmanifesta zero-uno-uno-molti Likes , ciascuno dei quali riguarda uno specifico Post .

Modelli logici

Quindi, da tale serie di asserzioni, ho derivato i due modelli di dati IDEF1X [1] di livello logico mostrati nella Figura 1 .

Figura 1 - Modelli di dati di persone e post

Opzione A

Come puoi vedere nel modello Opzione A, PersonId migra [2] da Persona Postcome CHIAVE ESTERA (FK), ma riceve il nome del ruolo [3] di AuthorIde questo attributo costituisce, insieme a PostNumber, la PRIMARY KEY (PK) del Posttipo di entità.

Si considera che un Likepuò esistere solo in relazione ad una particolare Post, quindi installato un LikePK che comprende tre diversi attributi: PostAuthorId, PostNumbere LikerId. La combinazione di PostAuthorIde PostNumberè un FK che fa il riferimento corretto al PostPK. LikerIdè, a sua volta, un FK che stabilisce l'associazione adatta con Person.PersonId.

Con l'aiuto di questa struttura, ti assicuri che una determinata persona possa manifestare una sola Likeoccorrenza nella stessa Postistanza.

Metodi per impedire a un autore di post di apprezzare il proprio post

Poiché non si desidera consentire la possibilità che una persona possa apprezzare i propri post creati, una volta nella fase di implementazione, è necessario stabilire un metodo che confronta il valore di Like.PostAuthorIdcon il valore di Like.LikerIdin ogni tentativo INSERT. Se detti valori corrispondono, (a) si rifiuta l'inserimento, se non corrispondono (b) si lascia che il processo continui.

Per eseguire questa attività nel database, è possibile utilizzare:

  1. UN VINCITORE DI CONTROLLO ma, ovviamente, questo metodo esclude MySQL, dal momento che non è stato implementato in questa piattaforma finora, come puoi vedere qui e qui .

  2. Righe di codice all'interno di una transazione ACID .

  3. Righe di codice all'interno di un TRIGGER , che potrebbero restituire un messaggio personalizzato che indica il tentativo di violazione della regola.

Opzione B

Se l'autore non è un attributo che identifica in modo primario un post nel tuo dominio aziendale, potresti scegliere una struttura simile a quella illustrata nell'opzione B.

Questo approccio assicura anche che un post possa essere apprezzato dalla stessa persona una sola volta.


Appunti

1. Integration Definition for Information Modeling ( IDEF1X ) è una tecnica di modellazione dei dati altamente raccomandabile che è stata definita come standard nel dicembre 1993 dal National Institute of Standards and Technology ( NIST ) degli Stati Uniti .

2. IDEF1X definisce la migrazione delle chiavi come "Il processo di modellizzazione del posizionamento della chiave primaria di un'entità padre o generica nella sua entità figlio o categoria come chiave esterna".

3. Un nome di ruolo è una denotazione assegnata a un attributo di chiave esterna al fine di esprimere il significato di tale attributo nel contesto del tipo di entità corrispondente. La denominazione dei ruoli è raccomandata dal 1970 dal dott. EF Codd nel suo saggio seminale intitolato "Un modello relazionale di dati per grandi banche dati condivise" . Da parte sua, IDEF1X - mantenere la fedeltà per quanto riguarda le pratiche relazionali - sostiene anche questa procedura.


6

Non vedo nulla di ciclico qui. Ci sono persone e posti e due relazioni indipendenti tra queste entità. Vorrei che i Mi piace fossero l'implementazione di una di queste relazioni.

  • Una persona può scrivere molti post, un post è scritto da una persona: 1:n
  • Una persona può avere molti post, un post può essere utile a molte persone: n:m
    il n: rapporto m può essere implementato con un altro rapporto: likes.

Implementazione di base

L'implementazione di base potrebbe apparire così in PostgreSQL :

CREATE TABLE person (
  person_id serial PRIMARY KEY
, person    text NOT NULL
);

CREATE TABLE post (
  post_id   serial PRIMARY KEY
, author_id int NOT NULL  -- cannot be anonymous
     REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE  -- 1:n relationship
, post      text NOT NULL
);

CREATE TABLE likes (  -- n:m relationship
  person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE
, post_id   int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE
, PRIMARY KEY (post_id, person_id)
);

Nota in particolare che un post deve avere un autore ( NOT NULL), mentre l'esistenza di mi piace è facoltativa. Per calibro esistenti, tuttavia, poste person devono entrambi essere referenziato (recepita con il PRIMARY KEYche fa entrambe le colonne NOT NULLautomaticamente (è possibile aggiungere questi vincoli in modo esplicito, in modo ridondante) in modo calibro anonimi sono anche impossibile.

Dettagli per l'implementazione n: m:

Prevenire il self-like

Hai anche scritto:

(alla persona creata non può piacere il proprio post).

Questo non è ancora applicato nell'implementazione sopra. Potresti usare un grilletto .
O una di queste soluzioni più veloci / più affidabili:

Solido per un costo

Se ha bisogno di essere solido come una roccia , si potrebbe estendere l'FK da likesa postper includere il author_idridondante. Quindi puoi escludere l'incesto con un semplice CHECKvincolo.

CREATE TABLE likes (
  person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE
, post_id   int 
, author_id int NOT NULL
, CONSTRAINT likes_pkey PRIMARY KEY (post_id, person_id)
, CONSTRAINT likes_post_fkey FOREIGN KEY (author_id, post_id)
     REFERENCES post(author_id, post_id) ON UPDATE CASCADE ON DELETE CASCADE
, CONSTRAINT no_self_like CHECK (person_id <> author_id)
);

Ciò richiede un UNIQUEvincolo altrimenti anche ridondante in post:

ALTER TABLE post ADD CONSTRAINT post_for_fk_uni UNIQUE (author_id, post_id);

Ho messo per author_idprimo a fornire un indice utile pur essendoci.

Risposta correlata con altro:

Più economico con un CHECKvincolo

Sulla base della "Implementazione di base" sopra.

CHECKi vincoli sono fatti per essere immutabili. Fare riferimento ad altre tabelle per un controllo non è mai immutabile, stiamo abusando un po 'del concetto qui. Suggerisco di dichiarare il vincolo NOT VALIDper riflettere adeguatamente quello. Dettagli:

Un CHECKvincolo sembra ragionevole in questo caso particolare, perché l'autore di un post sembra un attributo che non cambia mai. Non consentire gli aggiornamenti a quel campo per essere sicuri.

Abbiamo finto una IMMUTABLEfunzione di:

CREATE OR REPLACE FUNCTION f_author_id_of_post(_post_id int)
  RETURNS int AS
'SELECT p.author_id FROM public.post p WHERE p.post_id = $1'
LANGUAGE sql IMMUTABLE;

Sostituisci "pubblico" con lo schema reale delle tue tabelle.
Utilizzare questa funzione in un CHECKvincolo:

ALTER TABLE likes ADD CONSTRAINT no_self_like_chk
   CHECK (f_author_id_of_post(post_id) <> person_id) NOT VALID;

4

Penso che tu abbia difficoltà a capirlo a causa di come dichiari le tue regole aziendali.

Le persone e i post sono "oggetti". Like è un verbo.

Hai davvero solo 2 azioni:

  1. Una persona può creare uno o più post
  2. Molte persone possono apprezzare molti post. (una raccolta delle tue ultime 2 dichiarazioni)

alla gente piace il diagramma dei messaggi

La tabella "Mi piace" avrà person_id e post_id come chiave primaria.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.