Rag*_*agu 11 mysql postgresql database-design design-pattern
我有3张桌子:
当我设计 ER 模型时,它具有循环依赖关系:
1:N
人 --------< 帖子
1:N
发帖 ----------< 点赞
1:N
人们 --------< 喜欢
逻辑是:
1个人可以有很多帖子。
1个帖子有很多赞。
1个人可以点赞多个帖子(创建的人不能点赞自己的帖子)。
我怎样才能消除这种循环设计?还是我的数据库设计错了?
MDC*_*CCL 11
让我们对您提出的业务规则进行一些改写:
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)你让过程继续。
为了在您的数据库中完成此任务,您可以使用:
A CHECK CONSTRAINT但是,当然,此方法不包括 MySQL,因为到目前为止它尚未在此平台中实现,如您在此处和此处所见。
代码行内ACID事务。
代码行一个内触发,这可能会返回指示违反规则的企图自定义消息。
如果作者不是在您的业务领域中以主要方式标识帖子的属性,您可以采用类似于选项 B 中描述的结构。
这种方法还确保一个帖子只能被同一个人点赞一次。
1. 信息建模集成定义 ( IDEF1X ) 是一种非常值得推荐的数据建模技术,于1993 年 12 月被美国国家标准与技术研究院 ( NIST )定义为标准。
2. IDEF1X 将键迁移定义为“将父实体或通用实体的主键作为外键放置在其子实体或类别实体中的建模过程”。
3.角色名称是分配给外键属性的符号,目的是在其对应实体类型的上下文中表达该属性的含义。自 1970 年以来,EF Codd 博士在题为“大型共享数据库的数据关系模型”的开创性论文中推荐使用角色命名。就其本身而言,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)
);
Run Code Online (Sandbox Code Playgroud)
特别要注意的是,一个帖子必须有一个作者(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)
);Run Code Online (Sandbox Code Playgroud)
这需要一个另外的冗余UNIQUE约束post:
ALTER TABLE post ADD CONSTRAINT post_for_fk_uni UNIQUE (author_id, post_id);
Run Code Online (Sandbox Code Playgroud)
我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;
Run Code Online (Sandbox Code Playgroud)
用表的实际模式替换“public”。
在CHECK约束中使用此函数:
ALTER TABLE likes ADD CONSTRAINT no_self_like_chk
CHECK (f_author_id_of_post(post_id) <> person_id) NOT VALID;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9330 次 |
| 最近记录: |