Je ne vois rien de cyclique ici. Il existe des personnes et des postes et deux relations indépendantes entre ces entités. Je verrais les goûts comme la mise en œuvre de l'une de ces relations.
- Une personne peut écrire plusieurs articles, un article est écrit par une seule personne:
1:n
- Une personne peut comme de nombreux postes, un poste peut être aimé par de nombreuses personnes:
n:m
Le n: relation m peut être mis en œuvre avec une autre relation: likes.
Implémentation de base
L'implémentation de base pourrait ressembler à ceci dans 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)
);
Notez en particulier qu'un article doit avoir un auteur ( NOT NULL), alors que l'existence de likes est facultative. Pour les likes existants, cependant, postet person doivent tous deux être référencés (imposé par le PRIMARY KEYqui rend les deux colonnes NOT NULLautomatiquement (vous pouvez ajouter ces contraintes de manière explicite, redondante), donc les likes anonymes sont également impossibles.
Détails pour l'implémentation n: m:
Empêcher le self-like
Vous avez également écrit:
(la personne créée ne peut pas aimer son propre message).
Cela n'est pas encore appliqué dans la mise en œuvre ci-dessus. Vous pouvez utiliser un déclencheur .
Ou l'une de ces solutions plus rapides / plus fiables:
Solide comme un roc pour un coût
S'il doit être solide comme le roc , vous pouvez étendre le FK de likesà postpour l'inclure de manière author_idredondante. Ensuite, vous pouvez exclure l'inceste avec une simple CHECKcontrainte.
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)
);
Cela nécessite une UNIQUEcontrainte sinon également redondante dans post:
ALTER TABLE post ADD CONSTRAINT post_for_fk_uni UNIQUE (author_id, post_id);
Je mets d' author_idabord à fournir un indice utile tout en y étant.
Réponse connexe avec plus:
Moins cher avec une CHECKcontrainte
S'appuyant sur la «mise en œuvre de base» ci-dessus.
CHECKles contraintes sont censées être immuables. Référencer d'autres tables pour une vérification n'est jamais immuable, nous abusons un peu du concept ici. Je suggère de déclarer la contrainte NOT VALIDpour bien refléter cela. Détails:
Une CHECKcontrainte semble raisonnable dans ce cas particulier, car l'auteur d'un article semble être un attribut qui ne change jamais. Interdisez les mises à jour de ce champ pour être sûr.
On simule une IMMUTABLEfonction:
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;
Remplacez «public» par le schéma réel de vos tables.
Utilisez cette fonction dans une CHECKcontrainte:
ALTER TABLE likes ADD CONSTRAINT no_self_like_chk
CHECK (f_author_id_of_post(post_id) <> person_id) NOT VALID;