2010-05-07 115 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'), 

我希望这可以帮助你。
此致敬礼。