yii 外键关系和“属于多个”

nkkqxpd9  于 2022-11-09  发布在  其他
关注(0)|答案(4)|浏览(148)

编辑-基于下面的回答,我将重新审视我的设计。我想我可以通过更聪明地设置我的业务对象和规则来避免这种混乱。感谢大家的帮助!

我有以下模型:
S属于T
T有许多S
A、B、C、D、E(等等)各有1个T,所以T应属于A、B、C、D、E(等等)中的每一个
首先,我设置了外键,在A中,fk_a_t将是A.t到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,但我不清楚具体如何做到这一点(我会继续在谷歌上搜索更多)
EDIT -澄清一下,一个T只能属于A,或B,或C中的一个,(etc)而不是两个A,也不是一个A和一个B(也就是说,它不是多对多)我的问题是关于如何在Yii框架模型中描述这种关系-例如,(A,B,C,D,...)具有_ONE T,且T属于(A,B,C,D,...)从业务用例来看,这一切都是有意义的,但是我不确定我是否在数据库中正确地设置了它,或者如果我设置了,我需要在Yii中使用一个“行为”来让它理解关系。@rwmnau我明白你的意思,我希望我的澄清能有所帮助。
统一建模语言:x1c 0d1x
下面是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;
qpgpyjmq

qpgpyjmq1#

您的问题部分在于您无法区分它与哪个表相关。
此外,如果您只能有一个记录与其他三个或四个表中的任何一个匹配,则这不是正常的关系,无法使用正常技术建模。触发器可以确保这是真的,但其中只有id列,这会阻止它与表A中的id为10和表C中的id为10匹配(违反规则)。
顺便说一句,为列命名ID通常是一个糟糕的维护选择。如果您为PK使用表名来命名列,并为FK使用PK的确切名称,则会更清楚地了解发生了什么。
另一种解决方案是在中间表中为每种类型的id设置一列,并设置一个触发器,以确保只有其中一个id具有值,但如果需要所有id,则查询起来会很麻烦。id和idtype的复合PK可以确保在一个类型中没有重复,但要完全没有重复,则需要一个触发器。

gpnt7bae

gpnt7bae2#

这是一个经常出现的困境,恕我直言,没有完美的解决方案。
但是,我建议您:
把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个表才能强制执行该规则。

7bsow1i6

7bsow1i63#

如果是多对多关系,则只需要在中间放置一个表,但听起来并不是这样,所以不必担心这些问题。
您的问题不清楚-一个T是否可以属于多个A、多个B,等等?或者一个T是否属于A-E中的每一个,而不属于其他任何一个?这是一对一关系与(每个T正好有一个A-E)和一对多关系(每个A-E恰好有1个T,但一个T可以属于许多A、许多B,依此类推)。这有意义吗?
此外,我会在你的问题中提供更多信息,以帮助巩固你的要求。

jm81lzqq

jm81lzqq4#

几周前我不得不面对类似的情况(不是我自己的db,我更喜欢把所有的表合并成一个,除非在非常特定的情况下)。
我实施的解决方案是:在“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'),

我希望这对你有帮助。
祝你好运

相关问题