回答:
あなたが提示したビジネスルールをいくつか言い換えましょう:
Person
は0-one-or-manyを 作成しますPosts
。Post
は0-one-or-many を受け取りますLikes
。Person
マニフェストは、ゼロ一又は多 Likes
、WICHのそれぞれに関連する一つの特定の Post
。次に、そのような一連のアサーションから、図1に示す2つの論理レベルIDEF1X [1]データモデルを導出しました。
あなたはオプションAモデルで見ることができるように、PersonId
移行[2]からPerson
のPost
、それは受信FOREIGN KEY(FK)としてロール名[3]のをAuthorId
一緒に、この属性がアップになりPostNumber
、PRIMARY KEY(PK)Post
エンティティタイプ。
Like
は特定のに関連してのみ存在できると想定しているPost
ため、とのLike
3つの異なる属性で構成されるPKを設定しました。組み合わせとを適切な参照になりFKでPKを。次に、との適切な関連付けを確立するFKです。PostAuthorId
PostNumber
LikerId
PostAuthorId
PostNumber
Post
LikerId
Person.PersonId
この構造を利用して、決定された人がLike
同じPost
インスタンスに対して1つの発生のみを明示できることを保証します。
人が自分の作成した投稿を気に入ってしまう可能性を許容したくないので、実装フェーズに入るLike.PostAuthorId
とLike.LikerId
、すべてのINSERT試行のの値との値を比較するメソッドを確立する必要があります。上記の値が一致する場合は、(a)挿入を拒否し、一致しない場合は(b)プロセスを続行させます。
データベースでこのタスクを実行するには、以下を利用できます。
CHECK CONSTRAINTしかし、もちろん、この方法で除外のMySQL、あなたが見ることができるように、それは、これまでのところ、このプラットフォームでは実装されていないので、こことここ。
ACIDトランザクション内のコード行。
TRIGGER内のコード行。ルール違反の試行を示すカスタムメッセージを返す可能性があります。
著者が主な方法でビジネスドメインの投稿を識別する属性でない場合は、オプションBに示したものと同様の構造を使用できます。
このアプローチは、投稿が同じ人によって一度だけ高く評価されることも保証します。
1.情報モデリングの統合定義(IDEF1X)は、1993年12月に米国国立標準技術研究所(NIST)によって標準として定義された、非常に推奨されるデータモデリング手法です。
2. IDEF1Xは、キーの移行を「親エンティティまたはジェネリックエンティティの主キーを子またはカテゴリエンティティに外部キーとして配置するモデリングプロセス」と定義しています。
3. ロール名は、対応するエンティティタイプのコンテキストでそのような属性の意味を表すために、外部キー属性に割り当てられる表記です。ロールの命名は、1970年以来、EF Codd博士による「大規模な共有データバンクのデータのリレーショナルモデル」という独創的な論文で推奨されています。一方、IDEF1X(忠実に保つことはリレーショナルプラクティスを尊重する)もこの手順を支持しています。
ここで循環しているものは何もありません。人と投稿があり、これらのエンティティ間には2つの独立した関係があります。私はこれらの関係の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)
);
特に、投稿には著者(NOT NULL
)が必要ですが、いいねの存在はオプションです。既存の同類のために、しかし、post
とperson
しなければならないの両方によって強制(参照することがPRIMARY KEY
両方の列を作ることNOT NULL
に自動的に(あなたがそう匿名好きでも不可能です)重複し、明示的にこれらの制約を追加することができます。
n:m実装の詳細:
あなたも書いた:
(作成された人は自分の投稿を好きではありません)。
それは、上記の実装ではまだ強制されていません。トリガーを使用できます。
または、これらのより高速で信頼性の高いソリューションの1つ:
それがために必要がある場合堅実、あなたはから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;
あなたはあなたのビジネスルールをどのように述べているのか、これを理解するのが難しいと思います。
人と投稿は「オブジェクト」です。動詞です。
実際には2つのアクションがあります。
「いいね」テーブルには、主キーとしてperson_idとpost_idがあります。