Answers:
让我们对您提出的业务规则进行一些改写:
Person创建零一个或多个 Posts。Post收到零一个或多个 Likes。Person清单显示零一个或多个 Likes,每个都与一个特定的有关 Post。然后,从这样的一组断言中,我得出了图1所示的两个逻辑级别IDEF1X [1]数据模型。

正如可以在选项A型号见,PersonId 迁移[2]从Person以Post作为外键(FK),但它接收到的角色名称[3]的AuthorId具有和该属性构成,一起PostNumber,主键(PK)的所述Post实体的类型。
我假设Like只能与一个特定的连接存在Post,所以我已经设置了LikePK,3个不同的属性包括:PostAuthorId,PostNumber和LikerId。的组合PostAuthorId和PostNumber是一个FK,使适当的参考PostPK。LikerId反过来是FK,它与建立了适当的关联Person.PersonId。
借助这种结构,可以确保确定的人员只能Like在同一Post实例中出现一次。
由于您不希望某个人喜欢他/她撰写的文章,因此在实施阶段,您应该建立一种方法,将每次插入尝试中的值Like.PostAuthorId与值进行比较Like.LikerId。如果所述值匹配,则(a)您拒绝插入,如果它们不匹配(b),则让过程继续。
为了在数据库中完成此任务,可以使用:
如果作者不是主要标识您业务领域中帖子的属性,则可以采用类似于选项B中所述的结构。
这种方法还可以确保帖子只能被同一个人一次喜欢。
1.信息建模集成定义(IDEF1X)是一种高度推荐的数据建模技术,该技术已于1993年12月由美国国家标准技术研究院(NIST)定义为标准。
2. IDEF1X将密钥迁移定义为“将父或通用实体的主键放在其子或类别实体中作为外键的建模过程”。
3. 角色名称是指分配给外键属性的符号,目的是在其对应的实体类型的上下文中表达该属性的含义。EF Codd博士自1970年以来就在他的开创性论文《大型共享数据库的数据关系模型》中建议使用角色命名。就其本身而言,IDEF1X(保持忠实于关系实践)也提倡此过程。
我看不到这里有什么循环的。这些实体之间存在人员和职位以及两个独立的关系。我将喜欢视为这些关系之一的实现。
1:nn:mlikes。基本实现在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)
);
特别要注意的是,帖子必须有一个author(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;
我认为您很难确定这一点,因为您如何陈述自己的业务规则。
人和职位是“对象”。Like是一个动词。
您实际上只有2个动作:
“喜欢”表将person_id和post_id作为主键。