Як уникнути циклічної залежності (кругової посилання) між 3 таблицями?


10

У мене 3 таблиці:

  • Люди
  • Опублікувати
  • Любить

Коли я проектую модель ER, вона має циклічну залежність:

         1: N
Люди -------- <Опублікувати

         1: N
Повідомлення ---------- <Сподобалось

         1: N
Люди -------- <подобається

Логіка така:

  • 1 людина може мати багато постів.

  • 1 публікація має багато лайків.

  • 1 людина може сподобатися багатьом публікаціям (створеній людині не може подобатися його власна публікація).

Як я можу видалити такий циклічний дизайн? Або мій дизайн db неправильний?

Відповіді:


10

Правила бізнесу

Давайте внесемо кілька змін до представлених вами правил бізнесу:

  • A Personстворює нуль один або багато Posts .
  • A Postотримує нуль один або багато Likes .
  • А Personпроявляється нуль один або багато Likes , кожен з яких відноситься до однієї конкретної Post .

Логічні моделі

Потім з такого набору тверджень я отримав дві моделі даних IDEF1X [1] логічного рівня даних, які показані на малюнку 1 .

Рисунок 1 - Моделі даних людей і постів

Варіант А

Як ви можете бачити в моделі Варіант А, PersonId мігрує [2] з Personдо в Postякості зовнішнього ключа (FK), але він отримує ім'я ролі [3] з AuthorId, і цей атрибут становить, разом з PostNumberпервинним ключем (PK) від Postтипу об'єкта.

Я припускаю , що Likeможе існувати тільки в зв'язку з конкретним Post, так що я створив LikeПК , який складається з трьох різних атрибутів: PostAuthorId, PostNumberі LikerId. Поєднання PostAuthorIdі PostNumberє ФК, що робить належне посилання на PostПК. LikerIdце, в свою чергу, ФК, який встановлює відповідну асоціацію з Person.PersonId.

За допомогою цієї структури ви гарантуєте, що визначена людина може проявити лише одне Likeявище до одного і того ж Postекземпляра.

Методи заборонити автору пошти не сподобатися власній публікації

Оскільки ви не хочете допускати можливості того, щоб людині могли сподобатися його / її авторські пости, один раз на етапі впровадження, ви повинні встановити метод, який порівнює значення Like.PostAuthorIdзі значенням Like.LikerIdу кожній спробі INSERT. Якщо вказані значення збігаються, (а) ви відхиляєте вставку, якщо вони не відповідають (б), ви дозволяєте продовжувати процес.

Для виконання цього завдання у вашій базі даних можна скористатися:

  1. Перевірочне обмеження , але, звичайно ж , цей метод виключає MySQL, так як вона не була реалізована в цій платформі до сих пір, як ви можете бачити тут і тут .

  2. Рядки коду всередині транзакції ACID .

  3. Рядки коду в TRIGGER , які можуть повернути спеціальне повідомлення із зазначенням спроби порушення правила.

Варіант В

Якщо автор не є атрибутом, який первинно ідентифікує публікацію у вашому домені бізнесу, ви можете перейти зі структурою, подібною до тієї, що зображена у варіанті B.

Цей підхід також гарантує, що публікацію може сподобатися тією самою людиною лише один раз.


Примітки

1. Визначення інтеграції для інформаційного моделювання ( IDEF1X ) - це дуже рекомендована методика моделювання даних, яка була визначена як стандарт у грудні 1993 р. Національним інститутом стандартів і технологій США ( NIST ).

2. IDEF1X визначає міграцію ключів як "Процес моделювання розміщення первинного ключа батьківського або родового об'єкта в його дочірній або категорійній сутності як іноземний ключ".

3. Назва ролі - це позначення, присвоєне атрибуту іноземного ключа, щоб виразити значення такого атрибута в контексті відповідного типу сутності. Названня ролей рекомендується з 1970 р. Доктором Е. Ф. Коддом у своєму семінарському документі «Реляційна модель даних для великих спільних банків даних» . Зі свого боку, IDEF1X -keeping вірність стосується реляційного practices- також виступає за цю процедуру.


6

Я не бачу, щоб щось тут було циклічним. Між цими сутностями існують люди та посади та два незалежні стосунки. Я б бачив лайки як реалізацію одного з цих відносин.

  • Людина може написати багато дописів, допис пише одна людина: 1:n
  • Людина може любити багато постів, пост може бути улюбленим багатьма людьми: n:m
    п: відносини м можуть бути реалізовані з іншим співвідношенням: likes.

Основна реалізація

Основна реалізація може виглядати так у 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)
);

Зокрема, зауважте, що у публікації має бути автор ( NOT NULL), хоча наявність лайків необов’язково. Однак для існуючих лайків, postі вони person повинні бути посиланнями (примусові до того, PRIMARY KEYщо обидва стовпці роблять NOT NULLавтоматично (ви можете додати ці обмеження явно, надмірно), тому анонімні лайки також неможливі.

Деталі щодо n: m реалізації:

Запобігайте самолюбству

Ви також писали:

(створена особа не може сподобатися власній посаді).

Це все ще не виконується у зазначеній вище реалізації. Ви можете використовувати тригер .
Або одне з таких швидших / надійніших рішень:

Солідний за вартістю

Якщо він повинен бути непорушними , ви можете розширити FK від likesдо , postщоб включати в себе author_idвеликій кількості. Тоді ви можете виключити інцест з простим CHECKобмеженням.

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)
);

Для цього потрібне інакше також зайве UNIQUEобмеження у post:

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

Я ставлю author_idперше, щоб поставити корисний індекс , будучи в ньому.

Відповідна відповідь:

Дешевше з CHECKобмеженням

Спираючись на "Основну реалізацію" вище.

CHECKобмеження мають бути незмінні. Посилання на інші таблиці для перевірки ніколи не змінюються, ми тут трохи зловживаємо концепцією. Я пропоную оголосити обмеження, NOT VALIDщоб правильно відобразити це. Деталі:

У CHECKцьому конкретному випадку обмеження здається розумним, оскільки автор публікації здається атрибутом, який ніколи не змінюється. Вимкніть оновлення цього поля, щоб бути впевненим.

Ми підробленаIMMUTABLE функція:

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;

Замініть "public" фактичною схемою ваших таблиць.
Використовуйте цю функцію з CHECKобмеженням:

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

4

Думаю, у вас виникають труднощі з з'ясуванням цього через те, як ви заявляєте правила свого бізнесу.

Люди та пости - це "об'єкти". Like є дієсловом.

У вас дійсно всього дві дії:

  1. Людина може створити одну або кілька публікацій
  2. Багатьом людям можуть подобатися багато постів. (збірка ваших останніх 2 тверджень)

людям подобається діаграма повідомлень

У таблиці "подобається" в якості основного ключа будуть розміщуватися person_id та post_id.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.