許多:許多具有共享關係
我正在對具有多重性的數據進行建模,如下所示:
每個與作曲/選集相關的對必須共享一個作曲家。此外,每本選集必須至少包含一首作品。你會如何推薦我建模這個?
這是一種幾乎強制一致性的可能表示形式(它不強制 1+ Composition : 0+ Anthology 多重性)。然而,它在很多地方重複了 FK_Composer(作為一個煩惱,它破壞了我的一些實體框架功能)。
Composer Composition junction Anthology -------- ----------- -------------- --------- FK_Anthology -> PK PK <- FK_Composer <- FK_Composer -> FK_Composer PK <- FK_Composition
注意:我也在嘗試在業務邏輯和 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) );
這樣做的好處是它沒有多餘的數據不同步。問題在於,它不太符合香農的要求,即選集是關於一位作曲家的,並且該選集中的所有作品都必須來自同一個作曲家。
不幸的是,使用聲明性引用約束來解決這個問題並不容易。聲明性約束非常適合確保一行中的所有內容都有意義。它們不是為了在行之間強制執行規則而建構的。
有一種聲明式的方法可以解決這個問題,但它涉及到許多人不喜歡的權衡,因為它聞起來很像違反規範化。有些人會爭辯說(我想到了 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) );
請注意,這種工作方式是您必須通過使作曲家成為選集主鍵的一部分來將單個作曲家強加到選集上。你對作曲做同樣的事情。然後,當您在作曲和選集之間創建交集時,您將擁有兩次作曲家 ID。然後,您可以使用檢查約束以聲明方式強制要求作品和選集不僅有一個作曲家,而且是同一個作曲家。
注意:我不是說你應該這樣做,我只是說你可以這樣做。YMMV 等