web-dev-qa-db-ja.com

3つのテーブル間の循環依存(循環参照)を回避するにはどうすればよいですか?

3つのテーブルがあります。

  • 役職
  • いいね

ERモデルを設計すると、循環依存関係があります。

 1:N 
人-------- <投稿
 
 1:N 
投稿------- --- <いいね
 
 1:N 
人-------- <いいね

ロジックは次のとおりです。

  • 1人が多くの投稿を持つことができます。

  • 1件の投稿に多くの高評価があります。

  • 1人が多くの投稿を高く評価できます(作成された人は自分の投稿を高く評価できません)。

この種の循環設計を削除するにはどうすればよいですか?または私のdb設計は間違っていますか?

10
Ragu

ビジネスルール

あなたが提示したビジネスルールにいくつかの言い換えをさせてください:

  • Personzero-one-or-manyPostsを作成します。
  • Postzero-one-or-manyLikesを受け取ります。
  • Personマニフェストzero-one-or-manyLikeseach of wich関係するone specificPost

論理モデル

次に、そのような一連のアサーションから、2つの論理レベルIDEF1X[1]図1 に示されているデータモデル。

Figure 1 - People and Posts Data Models

オプションA

オプションAモデルでわかるように、PersonIdmigrates[2]PersonからPostまでを外部キー(FK)として使用しますが、ロール名を受け取ります[3] of AuthorId、およびこの属性は、PostNumberとともに、Postエンティティタイプの主キー(PK)を構成します。

Likeは特定のPostに関連してのみ存在できると想定しているため、3つの異なる属性で構成されるLike PKを設定しました:PostAuthorIdPostNumberおよびLikerIdPostAuthorIdPostNumberの組み合わせは、Post PKへの適切な参照を行うFKです。 LikerIdは、_Person.PersonId_との適切な関連付けを確立するFKです。

この構造を利用して、決定された人が同じLikeインスタンスに対して単一のPost発生のみを明示できることを保証します。

投稿者が自分の投稿を好きにならないようにする方法

あなたはしないある人が自分の作成した投稿を好きになる可能性を許可したいので、実装フェーズで、_Like.PostAuthorId_の値を比較するメソッドを確立する必要がありますINSERTを試行するたびに_Like.LikerId_の値。上記の値が一致する場合は(a)挿入を拒否し、一致しない場合は(b)プロセスを続行します。

データベースでこのタスクを実行するには、以下を利用できます。

  1. A CHECK CONSTRAINTですが、 here および here を確認できるように、このメソッドはこれまでこのプラットフォームに実装されていないため、MySQLを除外します。

  2. コード行ACIDトランザクションの内部

  3. コード行[〜#〜]トリガー[〜#〜]内で、ルール違反の試みを示すカスタムメッセージを返す可能性があります。

オプションB

著者が主な方法でビジネスドメインの投稿を識別する属性でない場合は、オプションBに示したものと同様の構造を使用できます。

このアプローチにより、同じ人物が投稿を高く評価できるのは1回だけです。


ノート

1.情報モデリングの統合定義(IDEF1X)は、12月に標準として定義された非常に推奨されるデータモデリング手法です。 1993年、米国国立標準技術研究所([〜#〜] nist [〜#〜])。

2. IDEF1Xはkey migrationを「親エンティティまたはジェネリックエンティティの主キーをその子エンティティまたはカテゴリエンティティに外部キーとして配置するモデリングプロセス」と定義しています。

3. ロール名は、対応するエンティティタイプのコンテキストでそのような属性の意味を表すために、外部キー属性に割り当てられる表記です。 Dr。 E. F.コッド「大規模な共有データバンクのデータのリレーショナルモデル」というタイトルの彼の独創的な論文。 IDEF1X(忠実性を尊重するrelationalプラクティスを維持する)もこの手順を支持しています。

10
MDCCL

ここで循環しているものは何もありません。 peoplepostsがあり、これらのエンティティ間に2つの独立した関係があります。私はlikesをこれらの関係の1つの実装と見なします。

  • 人は多くの投稿を書くことができ、投稿は一人で書かれます:1:n
  • 人は多くの投稿を高く評価でき、投稿は多くの人が高く評価できます:n:m
    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)
);

特に、投稿mustには著者(NOT NULL)、likeの存在はオプションです。ただし、既存のいいね!の場合、postpersonmustの両方が参照されます(PRIMARY KEY両方の列を作成しますNOT NULL自動的に(これらの制約を明示的に、冗長に追加する可能性があります)、匿名のlikeも不可能です。

N:m実装の詳細:

自己ライクを防ぐ

あなたも書いた:

(作成された人は自分の投稿を好きではありません)。

それは、上記の実装ではまだ強制されていません。 trigger を使用できます。
またはこれらのより高速で信頼性の高いソリューションの1つ:

コストに対して堅実

rock-solidにする必要がある場合は、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制約は妥当なように見えます。なぜなら、投稿の作成者は、決して変更されない属性のように見えるからです。確実にそのフィールドへの更新を禁止します。

我々fakeIMMUTABLE関数:

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

あなたはあなたのビジネスルールをどのように述べているのか、これを理解するのが難しいと思います。

人と投稿は「オブジェクト」です。動詞です。

実際には2つのアクションがあります。

  1. 人は1つ以上の投稿を作成できます
  2. 多くの人が多くの投稿を好きになることができます。 (最後の2つのステートメントの編集)

people like posts diagram

「いいね」テーブルには、主キーとしてperson_idとpost_idがあります。

4