具有兩種可能的所有者/父類型的實體的數據庫模式?
我正在使用帶有Sequelize的 PostgreSQL作為我的 ORM。
我有一種類型,
User
. 第二種類型是Group
,它可以通過一個GroupMemberships
表關聯任意數量的使用者。User
s 也可以擁有任意數量的Group
s。我的第三種類型 ,
Playlist
可以屬於 aUser
或 agroup
。為這種類型設計模式的最佳方法是什麼,以便它可以擁有一種類型的所有者或任何一種?我的第一遍創建了兩個關聯,但一次只填充了一個。這可能可行,但看起來很hacky並且使查詢變得困難。
附加資訊
以下是我對 MDCCL 通過評論發布的澄清請求的回應:
(1) 如果一個播放列表屬於給定組,可以說這個播放列表與一對多使用者相關,只要他們是該組的**成員,對嗎?
我相信這在技術上是正確的,但是這種一對多的關聯並不明確存在。
(2) 那麼,一個特定的播放列表是否可以同時由一對多的組擁有?
不, a 不可能
Playlist
由 one-to-many 擁有Groups
。(3) 特定播放列表是否可以由一對多組擁有,同時由不是該組**成員的一對多使用者擁有?
不,因為如(2)中的一對多 from
Playlist
toGroup
不應該存在。此外,如果 aPlaylist
由 a 擁有,Group
則它不屬於 aUser
,反之亦然。一次只有一個所有者。(4) 用於唯一標識組、使用者和播放列表的屬性是什麼?
它們每個都有一個代理主鍵 (
id
) 和一個自然鍵(雖然不是主鍵)。這些slug
是Group
和Playlist
,和username
。User
(5) 特定播放列表是否會發生所有者更改?
儘管我不打算將其作為一個功能(至少最初是這樣),但我認為這可能會發生。
(6) Group.Slug和Playlist.Slug屬性是什麼意思?它們的值是否足夠穩定,可以定義為主鍵,還是經常更改?這兩個屬性的值以及User.Username必須是唯一的,對嗎?
這些
slug
s 是其各自實體的唯一、小寫、連字元版本title
。例如,group
帶有title
“測試組”的 a 將具有slug
“測試組”。重複項附加了增量整數。這將隨時改變他們的title
變化。我相信這意味著他們不會做出很好的主鍵?是的,slugs
並且usernames
在各自的表格中是獨一無二的。
如果我正確理解了您的規範,那麼您的場景涉及(除其他重要方面外)超類型 - 子類型結構。
我將在下面舉例說明如何(1)在抽象的概念級別對其進行建模,然後(2)在邏輯級別的DDL 設計中表示它。
商業規則
以下概念公式是您業務環境中最重要的規則之一:
- 播放列表在特定時間點由一個組或一個使用者擁有
- 播放列表可能由一對多組或使用者在不同時間點擁有
- 使用者擁有零個或多個播放**列表
- A Groups擁有零個一個或多個播放列表
- 一個組由一對多的成員(必須是使用者)組成
- 使用者可能是零一或多組的成員。
- 一個組由一對多的成員(必須是使用者)組成
由於 (a) User和Playlist之間以及 (b) Group和Playlist之間的關聯或關係非常相似,這一事實表明User和Group是Party 1的互斥實體子類型,而後者又是它們的實體超類型 -supertype-子類型集群是經典的資料結構,出現在非常多樣化的概念模式中——。以這種方式,可以斷言兩個新規則:
- 派對僅由一個PartyType分類
- 一方是組或使用者_
之前的四個規則必須重新表述為只有三個:
- 播放列表在特定時間點僅由一方擁有
- 播放列表可能由一對多方在不同時間點擁有
- 一方擁有零個或多個播放列表
說明性IDEF1X圖
圖 1所示的 IDEF1X 2圖表整合了所有上述業務規則以及其他相關的規則:
如圖所示,Group和User被描繪為子類型,它們通過各自的線和與超類型Party的**專有符號連接。
Party.PartyTypeCode屬性代表子類型鑑別**器,即它指示哪種子類型實例必須補充給定的超類型出現。
此外,Party通過OwnerId屬性與Playlist連接,該屬性被描述為指向Party.PartyId的 FOREIGN KEY 。通過這種方式,Party將 (a) Playlist與 (b) Group和 (c) User相互關聯。
因此,由於特定的Party實例是Group或User,特定的播放列表最多可以與一個子類型出現連結。
說明性邏輯級佈局
之前闡述的 IDEF1X 圖為我提供了創建以下邏輯 SQL-DDL 排列的平台(並且我提供了註釋作為註釋,突出了幾個特別相關的點——例如,約束聲明——):
-- You should determine which are the most fitting -- data types and sizes for all your table columns -- depending on your business context characteristics. -- Also, you should make accurate tests to define the -- most convenient INDEX strategies based on the exact -- data manipulation tendencies of your business domain. -- As one would expect, you are free to utilize -- your preferred (or required) naming conventions. CREATE TABLE PartyType ( -- Represents an independent entity type. PartyTypeCode CHAR(1) NOT NULL, Name CHAR(30) NOT NULL, -- CONSTRAINT PartyType_PK PRIMARY KEY (PartyTypeCode), CONSTRAINT PartyType_AK UNIQUE (Name) ); CREATE TABLE Party ( -- Stands for the supertype. PartyId INT NOT NULL, PartyTypeCode CHAR(1) NOT NULL, -- Symbolizes the discriminator. CreatedDateTime TIMESTAMP NOT NULL, -- CONSTRAINT Party_PK PRIMARY KEY (PartyId), CONSTRAINT PartyToPartyType_FK FOREIGN KEY (PartyTypeCode) REFERENCES PartyType (PartyTypeCode) ); CREATE TABLE UserProfile ( -- Denotes one of the subtypes. UserId INT NOT NULL, -- To be constrained as both (a) the PRIMARY KEY and (b) a FOREIGN KEY. UserName CHAR(30) NOT NULL, FirstName CHAR(30) NOT NULL, LastName CHAR(30) NOT NULL, GenderCode CHAR(3) NOT NULL, BirthDate DATE NOT NULL, -- CONSTRAINT UserProfile_PK PRIMARY KEY (UserId), CONSTRAINT UserProfile_AK1 UNIQUE ( -- Multi-column ALTERNATE KEY. FirstName, LastName, GenderCode, BirthDate ), CONSTRAINT UserProfile_AK2 UNIQUE (UserName), -- Single-column ALTERNATE KEY. CONSTRAINT UserProfileToParty_FK FOREIGN KEY (UserId) REFERENCES Party (PartyId) ); CREATE TABLE MyGroup ( -- Represents the other subtype. GroupId INT NOT NULL, -- To be constrained as both (a) the PRIMARY KEY and (b) a FOREIGN KEY. Title CHAR(30) NOT NULL, -- CONSTRAINT Group_PK PRIMARY KEY (GroupId), CONSTRAINT Group_AK UNIQUE (Title), -- ALTERNATE KEY. CONSTRAINT GroupToParty_FK FOREIGN KEY (GroupId) REFERENCES Party (PartyId) ); CREATE TABLE Playlist ( -- Stands for an independent entity type. PlaylistId INT NOT NULL, OwnerId INT NOT NULL, Title CHAR(30) NOT NULL, CreatedDateTime TIMESTAMP NOT NULL, -- CONSTRAINT Playlist_PK PRIMARY KEY (PlaylistId), CONSTRAINT Playlist_AK UNIQUE (Title), -- ALTERNATE KEY. CONSTRAINT PartyToParty_FK FOREIGN KEY (OwnerId) -- Establishes the relationship with (a) the supertype and (b) through the subtype with (c) the subtypes. REFERENCES Party (PartyId) ); CREATE TABLE GroupMember ( -- Denotes an associative entity type. MemberId INT NOT NULL, GroupId INT NOT NULL, IsOwner BOOLEAN NOT NULL, JoinedDateTime TIMESTAMP NOT NULL, -- CONSTRAINT GroupMember_PK PRIMARY KEY (MemberId, GroupId), -- Composite PRIMARY KEY. CONSTRAINT GroupMemberToUserProfile_FK FOREIGN KEY (MemberId) REFERENCES UserProfile (UserId), CONSTRAINT GroupMemberToMyGroup_FK FOREIGN KEY (GroupId) REFERENCES MyGroup (GroupId) );
當然,您可以進行一項或多項調整,以便在實際數據庫中以所需的精度表示業務上下文的所有特徵。
注意:我已經在這個 db<>fiddle和這個 SQL Fiddle上測試了上面的邏輯佈局,它們都在 PostgreSQL 9.6 上“執行”,所以你可以看到它們“在執行”。
蛞蝓
如您所見,我沒有在 DDL 聲明中包含
Group.Slug
也不Playlist.Slug
作為列。之所以如此,是因為,與您的以下解釋一致這些
slug
s 是其各自實體的唯一、小寫、連字元版本title
。例如,group
帶有title
“測試組”的 a 將具有slug
“測試組”。重複項附加了增量整數。這將隨時改變他們的title
變化。我相信這意味著他們不會做出很好的主鍵?是的,slugs
並且usernames
在各自的表格中是獨一無二的。可以得出結論,它們的值是可導出的(即,它們必鬚根據對應的
Group.Title
和Playlist.Title
值來計算或計算,有時與 - 我假設,某種系統生成的 - INTEGER 結合使用),所以我不會聲明所述列在任何基表中,因為它們會引入更新異常。相反,我會生產
Slugs
- 也許,在一個視圖中,(a)包括虛擬列中這些值的派生,(b)可以直接用於進一步的 SELECT 操作——附加 INTEGER 部分可以獲得,例如,通過組合(1)的值帶有 (2) 中間連
Playlist.OwnerId
字元和 (3) 的值Playlist.Title
;- 或者,通過應用程式碼,模仿之前描述的方法(可能在程序上),一旦相關數據集被檢索並格式化以供最終使用者解釋。
以這種方式,這兩種方法中的任何一種都可以避免“更新同步”機制,如果
Slugs
它們保留在基表的列中,則該機制應該到位。完整性和一致性考慮
重要的是要提到 (i)每一
Party
行必須始終由 (ii)恰好其中一個代表子類型的表中的相應對應項進行補充,(iii) 必須“符合”Party.PartyTypeCode
列中包含的值——表示鑑別器——。以聲明的方式強制執行這種情況是非常有利的,但是沒有一個主要的 SQL 數據庫管理系統(包括 Postgres)提供了必要的工具來進行這樣的操作;因此,到目前為止,在ACID TRANSACTIONS中編寫過程程式碼是保證在您的數據庫中*始終滿足前面描述的情況的最佳選擇。*其他可能性是訴諸觸發器,但可以這麼說,它們很容易使事情變得不整潔。
可比案例
如果您想建立一些類比,您可能有興趣查看我對題為的(較新)問題的回答
因為討論了可比較的場景。
尾註
1 Party是法律上下文中使用的術語,指的是組成單個實體的**個人或一,因此該名稱適用於代表使用者和集團在相關業務環境方面的概念。
2 資訊建模集成定義( IDEF1X ) 是一種高度推薦的數據建模技術,於 1993 年 12 月由美國國家標準與技術研究院(NIST)確立為*標準。*它完全基於 (a) 由關係模型的唯一創始人,即EF Codd 博士撰寫的一些早期理論著作;(b)由PP Chen 博士開發的實體關係視圖;以及 (c) Robert G. Brown 創建的邏輯數據庫設計技術。