映射到多个主键的外键列
Posted
技术标签:
【中文标题】映射到多个主键的外键列【英文标题】:Foreign Key column mapped to multiple primary keys 【发布时间】:2014-03-04 16:40:36 【问题描述】:我有一个包含三个表的数据库
消息 - PK = MessageId 草稿 - PK = DraftId 历史 - FK = RelatedItemId
History 表有一个外键 [RelatedItemId]
,它映射到 Messages
和 Drafts
中的两个主键之一。
这种关系有名称吗?
这只是糟糕的设计吗?
有没有更好的方法来设计这种关系?
以下是该问题的 CREATE TABLE 语句:
CREATE TABLE [dbo].[History](
[HistoryId] [uniqueidentifier] NOT NULL,
[RelatedItemId] [uniqueidentifier] NULL,
CONSTRAINT [PK_History] PRIMARY KEY CLUSTERED ( [HistoryId] ASC )
)
CREATE TABLE [dbo].[Messages](
[MessageId] [uniqueidentifier] NOT NULL,
CONSTRAINT [PK_Messages] PRIMARY KEY CLUSTERED ( [MessageId] ASC )
)
CREATE TABLE [dbo].[Drafts](
[DraftId] [uniqueidentifier] NOT NULL,
CONSTRAINT [PK_Drafts] PRIMARY KEY CLUSTERED ( [DraftId] ASC )
)
【问题讨论】:
最好提供CREATE
声明。在某些 rdbms 中,您可以像 SHOW CREATE TABLE Messages;
一样检索它
我发现很难选择答案,因此掷骰子...
【参考方案1】:
简而言之,您使用的解决方案称为:多态关联 目标:引用多个父母结果反-pattern: 使用双重用途外键,违反第一范式(原子问题),失去参照完整性 解决方案: 简化关系 More information about the problem .
顺便说一句,创建一个通用的超级表将帮助您:
【讨论】:
【参考方案2】:这种关系有名称吗?
我知道没有标准名称,但我听说有人使用“通用 FK”甚至“inner-platform effect"”这个词。
这只是糟糕的设计吗?
是的。
原因:它阻止您声明 FOREIGN KEY,因此阻止 DBMS 直接强制执行参照完整性。因此,您必须通过命令式代码(surprisingly difficult)强制执行它。
有没有更好的方法来设计这种关系?
是的。
为每个引用的表创建单独的 FOREIGN KEY。使它们可以为 NULL,但通过 CHECK 约束确保其中一个是非 NULL。
或者,看看inheritance。
【讨论】:
Talspaugh27 的回答是否消除了您对参照完整性的担忧? @bnieland 好吧,它允许两个连接,您特别指出它“映射到一个”。但即使假设这是固定的,我也看不出它会如何避免我在链接中提到的竞争条件。它是特定于 DBMS 的(不仅仅是在语法上,一些 DBMS 根本不支持引用其他行或表的 CHECK)。而且它的性能可能不如“原生”FK。并且不那么明显和自我记录。好的,我现在停止抨击它;) @bnieland 话虽如此,仔细实现类似的想法(避免竞争条件)可以为您节省一堆 NULL,但无论如何 NULL 往往很便宜(尤其是在 MS SQL Server 下, Oracle 略少,YMMV)。【参考方案3】:我发现的最佳实践是创建一个函数,返回传入的值是否存在于您的 Messages 和 Drafts PK 列中。然后,您可以在调用此函数的 History 列上添加一个约束,并且只有在它通过时才会插入(即它存在)。
添加未解析的示例代码:
CREATE FUNCTION is_related_there ( IN @value 唯一标识符) 返回小音 开始 IF (从 DraftId = @value 的草稿中选择 count(DraftId) + 从 MessageId = @value 的消息中选择 count(MessageId) > 0 THEN 返回 1; 别的 返回 0; 万一; 结束;
ALTER TABLE 历史记录添加约束 CK_HistoryExists CHECK (is_related_there (RelatedItemId) = 1)
希望运行和帮助大声笑
【讨论】:
一个很好的答案,我希望看看其他人的想法! 它实际上是一种用于在以数据为中心的架构中处理多级继承的方法。已经看到它在 Java 和 .net 应用程序中使用过以上是关于映射到多个主键的外键列的主要内容,如果未能解决你的问题,请参考以下文章
hibernate笔记--基于主键的单(双)向的一对一映射关系
当主键列是mysql中不同表的外键时,如何将主键列更改为自动递增