2010-05-07 69 views
1

編輯 - 基於以下回應,我將重新審視我的設計。我想我可以通過更加巧妙地闡述業務對象和規則來避免這種混亂。謝謝大家的幫助!外鍵關係和「屬於很多」

-

我有以下模式:

S所屬於到T

T具有許多小號

A,B,C,d,E(等)有1個T,因此T應該屬於A,B,C,D,E(等)中的每一個

起初,我設置了我的外鍵,因此在A中,fk_a_t將是At to T的外鍵(id),在B中它會是fk_b_t,等等在我的UML(使用MySQLWorkBench)中看起來很好,但是生成yii模型導致它認爲T有很多A,B,C,D(等等),這對我來說是相反的。

聽起來對我來說,或者我需要有A_T,B_T,C_T(等)表,但這會是一個痛苦,因爲有很多表有這種關係。我也一直在尋找更好的方式來做到這一點會是某種行爲,例如A,B,C,D(等)可以表現爲T,但我不清楚如何做到這一點(我會繼續谷歌更多在這)

編輯 - 澄清,T只能屬於A,B或C(等)之一,而不是兩個A,也不是A和B(即是,它不是很多)。我的問題是關於如何在Yii框架模型中描述這種關係 - 例如(A,B,C,D,...)HAS_ONE T,T屬於(A,B,C,D,.. )。從商業用例來看,這一切都是有道理的,但我不確定是否在數據庫中正確設置了它,或者如果我這樣做,我需要在Yii中使用「行爲」來使其理解關係。 @rwmnau我明白你的意思,我希望我的澄清有所幫助。

UML: uml diagram http://www.freeimagehosting.net/uploads/fd8efa2f1d.png

這裏的DDL(自動生成)。只是假設有3頁以上的表引用T.

-- ----------------------------------------------------- 
-- Table `mydb`.`T` 
-- ----------------------------------------------------- 
CREATE TABLE IF NOT EXISTS `mydb`.`T` (
    `id` INT NOT NULL AUTO_INCREMENT , 
    PRIMARY KEY (`id`)) 
ENGINE = InnoDB; 


-- ----------------------------------------------------- 
-- Table `mydb`.`S` 
-- ----------------------------------------------------- 
CREATE TABLE IF NOT EXISTS `mydb`.`S` (
    `id` INT NOT NULL AUTO_INCREMENT , 
    `thing` VARCHAR(45) NULL , 
    `t` INT NOT NULL , 
    PRIMARY KEY (`id`) , 
    INDEX `fk_S_T` (`id` ASC) , 
    CONSTRAINT `fk_S_T` 
    FOREIGN KEY (`id`) 
    REFERENCES `mydb`.`T` (`id`) 
    ON DELETE NO ACTION 
    ON UPDATE NO ACTION) 
ENGINE = InnoDB; 


-- ----------------------------------------------------- 
-- Table `mydb`.`A` 
-- ----------------------------------------------------- 
CREATE TABLE IF NOT EXISTS `mydb`.`A` (
    `id` INT NOT NULL AUTO_INCREMENT , 
    `T` INT NOT NULL , 
    `stuff` VARCHAR(45) NULL , 
    `bar` VARCHAR(45) NULL , 
    `foo` VARCHAR(45) NULL , 
    PRIMARY KEY (`id`) , 
    INDEX `fk_A_T` (`T` ASC) , 
    CONSTRAINT `fk_A_T` 
    FOREIGN KEY (`T`) 
    REFERENCES `mydb`.`T` (`id`) 
    ON DELETE NO ACTION 
    ON UPDATE NO ACTION) 
ENGINE = InnoDB; 


-- ----------------------------------------------------- 
-- Table `mydb`.`B` 
-- ----------------------------------------------------- 
CREATE TABLE IF NOT EXISTS `mydb`.`B` (
    `id` INT NOT NULL AUTO_INCREMENT , 
    `T` INT NOT NULL , 
    `stuff2` VARCHAR(45) NULL , 
    `foobar` VARCHAR(45) NULL , 
    `other` VARCHAR(45) NULL , 
    PRIMARY KEY (`id`) , 
    INDEX `fk_A_T` (`T` ASC) , 
    CONSTRAINT `fk_A_T` 
    FOREIGN KEY (`T`) 
    REFERENCES `mydb`.`T` (`id`) 
    ON DELETE NO ACTION 
    ON UPDATE NO ACTION) 
ENGINE = InnoDB; 


-- ----------------------------------------------------- 
-- Table `mydb`.`C` 
-- ----------------------------------------------------- 
CREATE TABLE IF NOT EXISTS `mydb`.`C` (
    `id` INT NOT NULL AUTO_INCREMENT , 
    `T` INT NOT NULL , 
    `stuff3` VARCHAR(45) NULL , 
    `foobar2` VARCHAR(45) NULL , 
    `other4` VARCHAR(45) NULL , 
    PRIMARY KEY (`id`) , 
    INDEX `fk_A_T` (`T` ASC) , 
    CONSTRAINT `fk_A_T` 
    FOREIGN KEY (`T`) 
    REFERENCES `mydb`.`T` (`id`) 
    ON DELETE NO ACTION 
    ON UPDATE NO ACTION) 
ENGINE = InnoDB; 
+0

你可以發佈圖表和/或DDL嗎?很高興看到它的外觀。 – 2010-05-07 18:39:13

+3

對我來說太抽象了。你可以發佈示例表結構嗎? – Oded 2010-05-07 18:39:38

+0

我已經添加了圖表和DDL,並希望澄清我的問題。 – jan 2010-05-07 19:15:27

回答

0

你只需要在中間有一個表,如果它是一個多一對多的關係,它聽起來不像是那樣的話,所以不要別擔心這些。

你的問題不清楚 - 一個T屬於多於1個A,多於1個B等等?或者一個T是否屬於A-E的每一個,而不是其他的?這是1對1關係(每個T只有一個AE)和一對多關係(每個AE只有1 T,但T可以屬於許多A,許多B,以及等等)。這有意義嗎?

此外,我會再次請求您的問題中的一些更多的信息,以幫助鞏固你要求的東西。

+0

我編輯過,希望能回答你的問題 - T不能超過1個A,B,C等。一個T屬於A-E,沒有其他人。 當我使用Yii自動創建模型時,它使得它們成爲HAS_MANY(這很好,很容易更改爲HAS_ONE),但後來我注意到T中的BELONGS_TO(它將BELONGS_TO設置爲使用它的最後一個模型)我很好奇,如果我讓很多FK指着不同的桌子來讓自己陷入麻煩。 – jan 2010-05-07 19:18:38

+0

@Jan - 你說得對,HAS_MANY會適應HAS_ONE,這聽起來真的是你想要的。擁有如此多的外鍵本身並不是一個問題,除非它增加了新行的過程,因爲它們必須按照特定的順序來完成(並且確保如果你的RDBMS支持「層疊刪除」對他們非常小心,因爲他們會在數據庫嚴重相關的時候破壞數據庫,只要你的外鍵不是圓形的,你就會好起來的 – SqlRyan 2010-05-07 19:54:40

1

你的問題部分是你無法區分它與哪個表相關。

此外,如果只能有一條記錄與三個或四個其他表中的任何一個相匹配,則這不是正常的關係,並且不能用普通技術建模。一個觸發器可以確保這是真實的,但只有id中的列可以防止它匹配表10中的表A和10中表C中的一個id(違反規則)。

順便說一句命名列ID通常是一個很差的維護選擇。如果你爲表名指定PK名稱並使用FK的Pk名稱,則會發生什麼更清晰的事情。

對於您來說,替代解決方案是在中間表中爲每種類型的ID和一個觸發器分配一列,以確保其中只有一個值具有值,但如果需要查詢所有ID,則很麻煩。一個id和idtype的化合物PK可以確保在一個類型中沒有重複,但是根本沒有重複,你需要一個觸發器。

+0

你說的對,沒有辦法看(A,B,C ..) 但是,這些模型(A,B,C)彼此之間的差異足夠大,我將永遠從A,B等到T進行工作。因此,T不能同時屬於A和B的規則本身不如T不能超過1同時(即對A的另一個約束,它的T是唯一的) 對於命名約定,爲簡單起見,我保持簡短。謝謝你的提示。 :) – jan 2010-05-07 19:57:37

1

這是一個相當經常出現的困境,並沒有完美的解決方案恕我直言。

但是,我會建議如下:

結合S和T表。我沒有看到T表的真正需求。

反轉A/B/C表格與S(以前的T)表格相關的方式。我的意思是在A/B/C端移除FK,並在S端創建可爲空的FK列。所以現在你的S表有三個額外的可空列:A_ID,B_ID,C_ID。

在S表上創建一個檢查約束,確保這些列中的某一列總是有一個值(或者如果允許,則沒有任何值)。

如果只有一個值是規則,則還可以跨這三列創建唯一約束,以確保只有一個S可以與A/B/C相關。

如果在這些列中沒有任何值是允許的,上面的規則也必須使用檢查約束來強制執行。

更新您的評論

確定後,然後我會忘記反轉的關係,並保持FK上的A/B/C側。我仍然會使用檢查約束來強制使用的唯一性,但是它需要跨表並且對於每種SQL類型(例如,SQL Server需要UDF跨越表中的檢查約束)可能看起來不同。我仍然認爲你可以摧毀T臺。

關於事物的ORM方面,我根本不知道yii,所以不能說那個。但是,如果您在數據庫級別強制執行關係,則通過代碼實現它的方式應該無關緊要,因爲數據庫負責數據的完整性(它們看起來像是與ORM的香草關係)。但是,如果在運行時違反檢查約束的規則,它可能會出現陷入特定錯誤的問題。

我還應該提到,如果有大量(甚至相當大)的數據進入有問題的表中,我推薦的方法可能不是最好的,因爲您的檢查約束必須檢查所有20個表來執行規則。

+0

不僅有3個與T有關的表格,接近20(在我真正的問題)。你是對的,我有T的唯一原因是有一個簡化的(?)A,B,C ......的方式有很多S.如果我覈實了T,那麼S就成爲所有fk_a,fk_b等欄目。正如其他評論所指出的那樣,A,B,C ......之間的獨特性並不是主要關心的問題 - 我更關心的是,我是以Yii(或其他ORM)能夠正確使用它的方式對其進行建模。 – jan 2010-05-07 20:22:26

+0

你說得很對。我認爲,因爲這會變得相當大,所以我需要重新思考我的設計,並擺脫我在開始時所做的一些假設。謝謝你的幫助! – jan 2010-05-07 20:36:18

0

幾周前我不得不面對類似的情況(不是我自己的db,我更喜歡將所有表合併成一個,除非在特定情況下)。
我實現的解決方案是:在「T」型文件我做的關係是這樣的()函數:

'id_1' => array(self::BELONGS_TO, 'A', 'id'), 
'id_2' => array(self::BELONGS_TO, 'B', 'id'), 
'id_3' => array(self::BELONGS_TO, 'C', 'id'), 

我希望這可以幫助你。
此致敬禮。