编辑 - 根据下面的回答,我将重新审视我的设计。我认为通过如何设置我的业务对象和规则更加聪明,我可以避免这种混乱。谢谢大家的帮助!
-
我有以下型号:
S属于T
T有很多S
A,B,C,D,E(等)各有1 T,因此T应属于A,B,C,D,E(等)中的每一个
首先我设置我的外键,以便在A中,fk_a_t将是At到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 :(得分:1)
您的问题部分在于您无法区分与之相关的表格。
此外,如果您只能有一个记录与三个或四个其他表中的任何一个匹配,则这不是正常关系,并且无法使用常规技术建模。触发器可以确保这是真的但是只有id的列阻止它匹配表A中的id和表C中的a的10(违反规则)。
BTW命名列ID通常是维护的不良选择。如果您使用PKs的表名称命名列并使用PK的确切名称来表示FK,则会更清楚。
另一种解决方案是在中间表中为每种类型的id和一个触发器提供一个列,以确保只有其中一个具有值,但如果您需要所有ID,则查询很麻烦。 id和idtype的复合PK可以确保一个类型中没有重复,但是根本没有重复,你需要一个触发器。
答案 1 :(得分: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的vanilla关系)。但是,如果在运行时违反了检查约束的规则,则可能会出现捕获特定错误的问题。
我还应该提一下,如果有大量(甚至是相当大的)数据进入相关表格,我推荐的方法可能不是最好的,因为您的检查约束必须检查所有20用于执行规则的表。
答案 2 :(得分:0)
如果它是多对多的关系,你只需要一个中间的桌子,并且听起来不是那样的,所以不要担心这些。
您的问题不明确 - T可以超过1 A,超过1 B,依此类推?或者单个T是属于每个A-E,还是没有其他的?它是1对1关系(每个T只有一个AE)和1对多关系(每个AE正好有1个T,但是T可以属于许多A,很多B,和等等)。这有意义吗?
此外,我还要求您提供更多信息,以帮助巩固您的要求。
答案 3 :(得分:0)
几周前我不得不面对类似的情况(不是我自己的数据库,我更喜欢将所有表合并为一个,除非在非常具体的情况下)。
我实现的解决方案是:在“T”模型文件中,我在relations()函数中执行了类似的操作:
'id_1' => array(self::BELONGS_TO, 'A', 'id'),
'id_2' => array(self::BELONGS_TO, 'B', 'id'),
'id_3' => array(self::BELONGS_TO, 'C', 'id'),
我希望这会对你有所帮助 问候。