sha*_*non 5 schema foreign-key database-design sql-server architecture
我正在对具有多重性的数据进行建模,如下所示:

每个 Composition/Anthology 相关对必须共享一个 Composer。此外,每本选集必须包含至少一个作品。你会如何推荐我建模这个?
这是一种几乎强制一致性的可能表示(它不强制 1+ Composition : 0+ Anthology 多样性)。然而,它复制了 FK_Composer 很多地方(作为副烦恼破坏了我的一些实体框架功能)。
Composer Composition junction Anthology
-------- ----------- -------------- ---------
FK_Anthology -> PK
PK <- FK_Composer <- FK_Composer -> FK_Composer
PK <- FK_Composition
Run Code Online (Sandbox Code Playgroud)
注意:我也在尝试在业务逻辑和 ORM 层解决这个问题,并且在那里也遇到了障碍。
我要问的问题是Anthology和之间的直接关系Composer对系统是否“重要”?任何系统中记录的有形事物之间都存在各种附带关系。但是,对于系统本身的目的,只有其中的某些是重要的。这些是属于关系模式的那些。
如果选集总是由乐曲组成,并且乐曲总是有作曲家,那么您总是可以使用查询推导出选集和作曲家之间的关系。如果你这样做,就不会有关系不一致的风险。
这个模型看起来像这样:

你会有这样的表定义:
create table Composer
( composer_id int IDENTITY
, composer_name nvarchar(50)
, biography nvarchar(1000) null
, other_composer_info nvarchar(1000) null
, constraint pk_composer primary key(composer_id)
);
create table Composition
( composition_id int IDENTITY
, composer_id int
, composition_name nvarchar(50)
, composed_on datetime
, constraint pk_composition primary key(composition_id)
, constraint fk_composition_composer
foreign key (composer_id) references Composer(composer_id)
);
create table Anthology
( anthology_id int IDENTITY
, anthology_name nvarchar(50)
, constraint pk_anthology primary key (anthology_id)
);
create table AnthologyItem
( anthology_id int
, composition_id int
, constraint pk_anthology_item primary key
(anthology_id, composition_id)
, constraint fk_item_anthology (anthology_id)
references Anthology(anthology_id)
, constraint fk_item_composition (composition_id)
references Composition(composition_id)
);
Run Code Online (Sandbox Code Playgroud)
这样做的好处是它没有多余的数据来不同步。问题是它不太符合香农的要求,即一部选集是关于一位作曲家的,并且该选集中的所有作品都必须出自同一位作曲家。
不幸的是,使用声明性引用约束来解决这不是一个容易的问题。声明约束是伟大的,确保一切都内一排是有道理的。它们不是为了执行行之间的规则而构建的。
有一种声明式方法可以解决这个问题,但它涉及许多人不喜欢的权衡,因为它闻起来很像违反规范化。有些人会争辩说(Mike Sherril 会想到)这个解决方案实际上并没有违反规范化规则,但是不太了解规范化实际规则的人可能会怀疑地看待这个解决方案。
那么这个有争议的解决方案是什么?它看起来像这样:

请注意,其中一些表的主键已被修改。这是解决方案的 SQL DDL:(您需要将其滚动到底部才能看到神奇之处。)
create table Composer
( composer_id int IDENTITY
, composer_name nvarchar(50)
, biography nvarchar(1000) null
, other_composer_info nvarchar(1000) null
, constraint pk_composer primary key(composer_id)
);
create table Composition
( composition_id int IDENTITY
, composer_id int
, composition_name nvarchar(50)
, composed_on datetime
, constraint pk_composition
primary key(composer_id, composition_id) -- NOTE CHANGE!
, constraint fk_composition_composer
foreign key (composer_id) references Composer(composer_id)
);
create table Anthology
( anthology_id int IDENTITY
, composer_id int -- THIS IS NEW!
, anthology_name nvarchar(50)
, constraint pk_anthology
primary key (composer_id, anthology_id) -- THIS IS DIFFERENT
);
create table AnthologyItem
( composer_id int -- THIS IS NEW!
, anthology_id int
, composition_id int
, constraint pk_anthology_item primary key -- THIS HAS CHANGED.
(composer_id, anthology_id, composition_id)
, constraint fk_item_anthology
foreign key (composer_id, anthology_id)
references Anthology(composer_id, anthology_id)
, constraint fk_item_composition
foreign key (composer_id, composition_id)
references Composition(composer_id, composition_id)
);
Run Code Online (Sandbox Code Playgroud)
请注意,这种工作方式是您必须通过使作曲家成为选集主键的一部分来将单个作曲家强加到选集中。你用合成做同样的事情。然后,当您在作品和选集之间创建交集时,您将拥有两次作曲家 ID。然后,您可以使用检查约束以声明方式强制要求作品和选集不仅有一个作曲家,而且有相同的作曲家。
注意:我不是说你应该这样做,我只是说你可以这样做。YMMV等