2013-01-13 71 views
-1

我準備一個傳統的Microsoft SQL Server數據庫,以便我可以通過一個ORM,如實體框架接口,我的問題圍繞處理一些我的多對多關聯有共同的類型。具體來說,是否應該在主類型之間共享一個通用類型,還是每個主類型都有自己的鏈接表?設置多對多表共享一個共同的類型

例如,下面是一個簡單的例子,我炮製,顯示感興趣的表如何目前設置:

legacy many-to-many

注意的有兩種類型,TeachersStudents,都可以包含零,一個或多個PhoneNumbers。兩個表TeachersStudents實際上共享關聯表(PeoplePhoneNumbers)。字段FKID可以是TeacherIdStudentId

我認爲這應該是設置的方法是這樣的:

better many-to-many?

這樣一來,無論是Teachers表和Students表獲得自己的PHONENUMBERS表。

我的直覺告訴我第二種方式是正確的。這是真的?即使PhoneNumbers表包含多個字段,該怎麼辦?我面向對象的程序員的大腦告訴我,如果這些表的唯一區別是它們鏈接到哪個主表,那麼有幾個相同的表都是錯誤的,每個表包含十幾個字段?例如:

redundant tables

在這裏,我們有一個包含相同信息的兩個表,但唯一的區別是,一個表是Teachers地址,另一種是Students。這些對我來說是多餘的,而且它們應該只是一張桌子 - 但是當我嘗試將ORM應用於此時,我失去了數據庫限制它們的能力(對嗎?),並且使它變得更加混亂。

這種類型的通用類型應該合併還是應該保持每個主類型的分離?

更新

下面這些問題的答案已指示我到下面的解決方案,它基於數據庫中的子類表。我最初的問題之一是我有一個公用表共享多個其他表,因爲該實體類型是其他表共用。處理該問題的正確方法是對共享表進行子類化,並從共同父節點實質上下降它們,並將常用數據類型鏈接到此新父節點。下面是一個例子(記住我實際的數據庫無關,與教師和學生,所以這個例子的高度製造,但其概念是有效的):

solution

由於TeachersStudents要求兩者PhoneNumbers中,解決方案是創建一個超類Party和FK PhoneNumbersParty表。另請注意,您仍然可以使用與Teachers相關的FK表,或者只與Students有關。在這個例子中,我還將StudentsPartTimeStudents分成了多個層次並從Learners下降。

這個解決方案非常令人滿意的地方是我在一個ORM中實現它,比如Entity Framework。

查詢很容易。我可以查詢所有教師和學生提供一個特定的電話號碼:

var partiesWithPhoneNumber = from p in dbContext.Parties 
    where p.PhoneNumbers.Where(x => x.PhoneNumber1.Contains(phoneNumber)).Any() 
    select p; 

,它只是簡單做了類似的查詢,但僅適用於僅屬於教師PHONENUMBERS:

var teachersWithPhoneNumber = from t in dbContext.Teachers 
    where t.Party.PhoneNumbers.Where(x => x.PhoneNumber1.Contains(phoneNumber)).Any() 
    select t; 

回答

2

老師和學生都是更一般概念(一個人)的子類。如果您創建一個Person表,該表包含爲數據庫中所有人共享的一般數據,然後創建鏈接到Person的Student和Teacher表幷包含任何其他詳細信息,則會發現您有適當的點鏈接到其他任何其他表。

如果有數據是所有人都通用的(例如從零到多個電話號碼),那麼您可以鏈接到Person表。如果您只有適合學生的數據,則將其鏈接到學生ID。您獲得額外的優勢,即學生輔導員只是一個既有學生記錄又有教師記錄的人員。

一些ORM直接支持子類表的概念。 LLBLGen以我描述的方式進行操作,因此您可以使數據訪問代碼與更高級別的概念(教師和學生)一起工作,Person表將以您的名義在低級數據訪問代碼中進行管理。

編輯

電流圖(這可能不是在源域這是從,所以建議一撮鹽翻譯相關的)上的某些評論。

黨,教師和學習者看起來不錯。如果您爲費率添加開始日期和結束日期,薪金看起來不錯,因此您可以跟蹤薪資歷史記錄。另外請記住,如果最終有多個具有Salary的實體,則可以使用PartyID(而不是TeacherID)。

PartyPhoneNumbers看起來像你可能會直接掛斷電話號碼。這取決於您是否希望一次更改多人(n:m)的電話號碼,或者每個參與方是否獨立擁有一個電話號碼。 (我希望後者是因爲你可能有一個學生是一個老師的孩子,因此他們共用一個電話號碼,我不希望更新學生的電話號碼來影響老師,所以)

學習者對PaymentHistories看起來不錯,但學生VS PartTimeStudents的差異似乎是人爲的。 (看起來像PartTimeStudents是更多的AttendenceDays,而這又是LearnerClasses連接的結果)。

+0

這已經簡潔地向我解釋了。我不喜歡我當前的數據庫是它有引用多個表的外鍵。現在,我瞭解如何安排我的表格,以便常見數據保留在公共數據中。我今天做了一些測試,將它帶入Entity Framework,並寫了一些很好的單元測試。我對這個結果很好,我對此非常有信心。 –

+0

引用多個表的外鍵實際上不是外鍵。它不能被數據庫強制執行(因爲沒有單獨的主表),它需要隨着時間的推移創建各種不規則的視圖來假裝客戶端代碼中沒有多個表。我很高興聽到您的初步測試進展順利。 – Godeke

1

的問題,你有一個「一對一」關係的例子。一個人是老師或學生(或可能是兩個人)。

我認爲現有的結構可以最好地捕獲這些信息。

該人有一個電話號碼。然後,有些人是老師,有些是學生。有關每個實體的附加信息都存儲在教師或學生表中。公用信息(如姓名)位於電話表中。

將電話號碼拆分爲兩個單獨的表格相當混亂。畢竟,電話號碼不知道是給學生還是老師。另外,您沒有其他電話號碼的空間,例如管理人員。對於有時可能教授或幫助教授課程的學生來說,您也會遇到一些挑戰。

0

讀你的問題,它看起來像你要求一個共同的數據庫模式,以您的情況。過去我見過幾種,比其他人更容易使用。

一個選項是讓Student_Address表和Teacher_Address表都使用相同的地址表。這種方式如果你有實體特定的領域來存儲,你有這種能力。但是,這可能會稍微(但不顯着)更難以查詢。

另一個選擇是你如何建議上述 - 我可能只是在表上添加一個主鍵。但是,您想要將一個PersonTypeId字段添加到該表(PersonTypeId鏈接到一個PersonType表)。這樣你就知道每個記錄是哪個實體。

我不會建議有兩個PhoneNumber表。我想你會發現在同一張桌子上維護所有內容要容易得多。我更喜歡將同一實體放在一起,這意味着學生是一個單一的實體,教師是一個單一的實體,PhoneNumbers是同一個事物。

祝你好運。

2

我想你應該看看超類型/亞型模式。添加PartyPerson表,每個老師或學生都有一行。然後,使用TeacherStudent表中的PartyID作爲PK和FK返回Party(但將它們命名爲TeacherIDStudentID)。這建立了超類型表與每個子類型表之間的「一對一或一」關係。

請注意,如果您在子類型表中具有標識列,則需要將其刪除。在創建這些實體時,您首先必須插入超類型,然後在任一子類中使用該行的ID。

爲了保持一致性,您還必須對其中一個子類型表進行重新編號,以便其ID不會與另一個表發生衝突。之後,您可以使用SET IDENTITY_INSERT ON創建丟失的超類型行。

這一切的美妙之處在於,當你有一個表,必須允許只有一種類型,例如Student可以FK到該表,但是當你需要一個FK這可以是 - 與您的Address表 - - 您的FK改爲Party表。

最後一點是將所有公共列移入超類型表中,並只將列放入子類型中,這些子類型之間必須有所不同。

您的單一Phone表現在很容易鏈接到PartyID

如需更詳細的解釋,請參閱this answer to a similar question

+0

謝謝@ErikE!你和戈德克爲我的問題提供了基本相同的答案。我希望我可以接受這兩種方式,但因爲我不能,所以我決定+1並接受Godeke並+1給你的答案,還+1 +1你的其他相關答案,因爲你的答案在提供例子時都很有幫助。 –

+0

Thanks @Brad!對於什麼是值得的,當兩個答案基本相同時,它是標準協議,與首先發布的答案一致。通過點擊問題右下方的「最舊」標籤,很容易看到發佈順序。 – ErikE