1

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

--

我有以下模型:

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图

这是 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;
4

4 回答 4

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 个表才能强制执行规则。

于 2010-05-07T20:08:00.153 回答
1

您的问题部分在于您无法区分它与哪些表相关。

此外,如果您只能有一个匹配三个或四个其他表中的任何一个的记录,这不是正常的关系,并且不能使用正常的技术进行建模。触发器可以确保这是真的,但只有 id 列阻止它匹配 10 的表 A 中的 id 和 10 的表 C 中的 anid(违反规则)。

顺便说一句,命名列 ID 通常是维护的糟糕选择。如果您使用表名为 PK 命名列,并为 FK 使用 Pk 的确切名称,则会更清楚发生了什么。

您的另一种解决方案是在中间表中为每种类型的 id 和一个触发器设置一个列,以确保它们中只有一个具有值,但是如果您需要所有 id,则查询起来很痛苦。id 和 idtype 的复合 PK 可以确保在一个类型中没有重复,但要完全没有重复,您将需要一个触发器。

于 2010-05-07T19:41:44.723 回答
0

如果它是多对多关系,则只需要在中间有一个表,而且听起来不是这样,所以不要担心这些。

您的问题不清楚 - T 是否可以属于超过 1 个 A、超过 1 个 B 等等?还是一个 T 属于每个 AE,而不属于其他?这是一对一的关系(每个 T 都有一个 AE)和一对多的关系(每个 AE 正好有 1 个 T,但是一个 T 可以属于许多 A、许多 B 和很快)。这有意义吗?

另外,我会在您的问题中提出更多信息的请求,以帮助巩固您的要求。

于 2010-05-07T18:53:37.080 回答
0

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

我希望这可以帮助你。
问候。

于 2010-05-12T20:23:47.120 回答