Comment éviter une dépendance cyclique (référence circulaire) entre 3 tables?

10

J'ai 3 tables:

  • Personnes
  • Publier
  • Aime

Lorsque je conçois le modèle ER, il a une dépendance cyclique:

         1: N
Personnes -------- <Message

         1: N
Poster ---------- <J'aime

         1: N
Personnes -------- <J'aime

La logique est:

  • 1 personne peut avoir plusieurs postes.

  • 1 poste a beaucoup de goûts.

  • 1 personne peut aimer de nombreux messages (une personne créée ne peut pas aimer son propre message).

Comment puis-je supprimer ce type de conception cyclique? Ou ma conception db est-elle incorrecte?

Ragu
la source

Réponses:

10

Règles métier

Laissez-nous reformuler les règles commerciales que vous avez présentées:

  • A Personcrée zéro un ou plusieurs Posts .
  • A Postreçoit zéro un ou plusieurs Likes .
  • Un Personmanifeste zéro-un ou plusieurs Likes , chacun appartenant à un spécifique Post .

Modèles logiques

Ensuite, à partir d'un tel ensemble d'assertions, j'ai dérivé les deux modèles de données IDEF1X [1] de niveau logique qui sont illustrés à la figure 1 .

Figure 1 - Modèles de données sur les personnes et les postes

Option A

Comme vous pouvez le voir dans le modèle Option A, PersonId migre [2] de Personvers en Posttant que CLÉ ÉTRANGÈRE (FK), mais il reçoit le nom de rôle [3] de AuthorId, et cet attribut constitue, avec PostNumberla CLÉ PRIMAIRE (PK) du Posttype d'entité.

Je suppose que Likene peut exister que dans le cadre d'un particulier Post, donc je l' ai mis en place un LikePK qui comprend trois attributs différents: PostAuthorId, PostNumberet LikerId. La combinaison de PostAuthorIdet PostNumberest un FK qui fait la référence appropriée au PostPK. LikerIdest, à son tour, un FK qui établit l'association appropriée avec Person.PersonId.

À l'aide de cette structure, vous vous assurez qu'une personne déterminée ne peut manifester qu'une seule Likeoccurrence dans la même Postinstance.

Méthodes pour empêcher un auteur de publication d'aimer sa propre publication

Étant donné que vous ne souhaitez pas autoriser une personne à aimer ses publications, une fois dans la phase de mise en œuvre, vous devez établir une méthode qui compare la valeur de Like.PostAuthorIdavec la valeur de Like.LikerIddans chaque tentative INSERT. Si ces valeurs correspondent, (a) vous rejetez l'insertion, si elles ne correspondent pas (b) vous laissez le processus se poursuivre.

Pour accomplir cette tâche dans votre base de données, vous pouvez utiliser:

  1. UNE CONTRAINTE DE CONTRÔLE mais, bien sûr, cette méthode exclut MySQL, car elle n'a pas été implémentée jusqu'à présent sur cette plateforme, comme vous pouvez le voir ici et ici .

  2. Lignes de code à l' intérieur d'une transaction ACID .

  3. Lignes de code dans un TRIGGER , qui pourraient renvoyer un message personnalisé indiquant la tentative de violation de règle.

Option B

Si l'auteur n'est pas un attribut qui identifie de manière principale une publication dans votre domaine d'activité, vous pouvez utiliser une structure similaire à celle décrite dans l'option B.

Cette approche garantit également qu'un message ne peut être aimé par la même personne qu'une seule fois.


Remarques

1. La définition d'intégration pour la modélisation de l'information ( IDEF1X ) est une technique de modélisation de données hautement recommandable qui a été définie comme norme en décembre 1993 par le National Institute of Standards and Technology ( NIST ) des États-Unis .

2. IDEF1X définit la migration de clé comme «Le processus de modélisation consistant à placer la clé primaire d'une entité parent ou générique dans son entité enfant ou catégorie comme clé étrangère».

3. Un nom de rôle est une dénotation attribuée à un attribut de clé étrangère afin d'exprimer la signification de cet attribut dans le contexte de son type d'entité correspondant. La dénomination des rôles est recommandée depuis 1970 par le Dr EF Codd dans son article fondateur intitulé «Un modèle relationnel de données pour les grandes banques de données partagées» . Pour sa part, IDEF1X - maintenir la fidélité vis-à- vis des pratiques relationnelles - prône également cette procédure.

MDCCL
la source
6

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;
Erwin Brandstetter
la source
4

Je pense que vous avez du mal à comprendre cela en raison de la façon dont vous énoncez vos règles commerciales.

Les personnes et les messages sont des "objets". Comme est un verbe.

Vous n'avez vraiment que 2 actions:

  1. Une personne peut créer un ou plusieurs articles
  2. De nombreuses personnes peuvent aimer de nombreux messages. (une compilation de vos 2 dernières déclarations)

les gens aiment le diagramme des messages

La table "likes" aura person_id et post_id comme clé primaire.

Nicolas de Fontenay
la source