3つのテーブルがあります。
ERモデルを設計すると、循環依存関係があります。
1:N 人-------- <投稿 1:N 投稿------- --- <いいね 1:N 人-------- <いいね
ロジックは次のとおりです。
1人が多くの投稿を持つことができます。
1件の投稿に多くの高評価があります。
1人が多くの投稿を高く評価できます(作成された人は自分の投稿を高く評価できません)。
この種の循環設計を削除するにはどうすればよいですか?または私のdb設計は間違っていますか?
あなたが提示したビジネスルールにいくつかの言い換えをさせてください:
Person
はzero-one-or-manyPosts
を作成します。Post
はzero-one-or-manyLikes
を受け取ります。Person
マニフェストzero-one-or-manyLikes
、each of wich関係するone specificPost
。次に、そのような一連のアサーションから、2つの論理レベルIDEF1X[1]図1 に示されているデータモデル。
オプションAモデルでわかるように、PersonId
migrates[2]Person
からPost
までを外部キー(FK)として使用しますが、ロール名を受け取ります[3] of AuthorId
、およびこの属性は、PostNumber
とともに、Post
エンティティタイプの主キー(PK)を構成します。
Like
は特定のPost
に関連してのみ存在できると想定しているため、3つの異なる属性で構成されるLike
PKを設定しました:PostAuthorId
、PostNumber
およびLikerId
。 PostAuthorId
とPostNumber
の組み合わせは、Post
PKへの適切な参照を行うFKです。 LikerId
は、_Person.PersonId
_との適切な関連付けを確立するFKです。
この構造を利用して、決定された人が同じLike
インスタンスに対して単一のPost
発生のみを明示できることを保証します。
あなたはしないある人が自分の作成した投稿を好きになる可能性を許可したいので、実装フェーズで、_Like.PostAuthorId
_の値を比較するメソッドを確立する必要がありますINSERTを試行するたびに_Like.LikerId
_の値。上記の値が一致する場合は(a)挿入を拒否し、一致しない場合は(b)プロセスを続行します。
データベースでこのタスクを実行するには、以下を利用できます。
A CHECK CONSTRAINTですが、 here および here を確認できるように、このメソッドはこれまでこのプラットフォームに実装されていないため、MySQLを除外します。
コード行ACIDトランザクションの内部 。
コード行[〜#〜]トリガー[〜#〜]内で、ルール違反の試みを示すカスタムメッセージを返す可能性があります。
著者が主な方法でビジネスドメインの投稿を識別する属性でない場合は、オプションBに示したものと同様の構造を使用できます。
このアプローチにより、同じ人物が投稿を高く評価できるのは1回だけです。
1.情報モデリングの統合定義(IDEF1X)は、12月に標準として定義された非常に推奨されるデータモデリング手法です。 1993年、米国国立標準技術研究所([〜#〜] nist [〜#〜])。
2. IDEF1Xはkey migrationを「親エンティティまたはジェネリックエンティティの主キーをその子エンティティまたはカテゴリエンティティに外部キーとして配置するモデリングプロセス」と定義しています。
3. ロール名は、対応するエンティティタイプのコンテキストでそのような属性の意味を表すために、外部キー属性に割り当てられる表記です。 Dr。 E. F.コッド「大規模な共有データバンクのデータのリレーショナルモデル」というタイトルの彼の独創的な論文。 IDEF1X(忠実性を尊重するrelationalプラクティスを維持する)もこの手順を支持しています。
ここで循環しているものは何もありません。 peopleとpostsがあり、これらのエンティティ間に2つの独立した関係があります。私はlikesをこれらの関係の1つの実装と見なします。
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)
);
特に、投稿mustには著者(NOT NULL
)、likeの存在はオプションです。ただし、既存のいいね!の場合、post
とperson
mustの両方が参照されます(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;