5

我们有一个数据库模式,以简化(略微做作)的形式,看起来像:

在此处输入图像描述

在列(domainId、groupId)上设置从用户到域的外键,以保证引用完整性。这种结构可以很好地达到预期目的。


但是,对于与同一个数据库通信的新应用程序,我现在需要为 Doctrine 创建一个映射以映射上述结构,包括列上的外键关系。

我尝试了以下方法:

<entity name="User" table="users">
   <!-- other fields -->
   <many-to-one field="domain" target-entity="Domain" fetch="LAZY">
      <join-columns>
         <join-column name="domainId" referenced-column-name="domainId"/>
         <join-column name="groupId" referenced-column-name="groupId"/>
      </join-columns>
   </many-to-one>
</entity>

但这给了我一个错误: UnitOfWork.php line 2649: Undefined index: groupId

所以,我的问题是:

在 Doctrine 中描述多列多对一外键关系的正确方法是什么?



为了完整起见,数据库为上面 ERD 中描述的模式创建代码:

CREATE TABLE `users` (
  `userId` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `groupId` INT(10) UNSIGNED NOT NULL,
  `domainId` INT(10) UNSIGNED NOT NULL,
  `someData` VARCHAR(32),
  PRIMARY KEY (`userId`),
  KEY `key_users_groupId_domainId` (`groupId`, `domainId`)
) ENGINE=InnoDB;

CREATE TABLE `domains` (
  `domainId` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `groupId` INT(10) UNSIGNED NOT NULL,
  `someOtherData` VARCHAR(32),
  PRIMARY KEY (`domainId`),
  KEY `key_domains_groupId` (`groupId`)
) ENGINE=InnoDB;


CREATE TABLE `groups` (
  `groupId` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `someMoreData` VARCHAR(32),
  PRIMARY KEY (`groupId`)
) ENGINE=InnoDB;


ALTER TABLE `users`
    ADD CONSTRAINT `fk_users_domains` FOREIGN KEY (`groupId`, `domainId`) REFERENCES `domains` (`groupId`, `domainId`),
    ADD CONSTRAINT `fk_users_groups` FOREIGN KEY (`groupId`) REFERENCES `groups` (`groupId`);

ALTER TABLE `domains`
    ADD CONSTRAINT `fk_domains_groups` FOREIGN KEY (`groupId`) REFERENCES `groups` (`groupId`);
4

1 回答 1

3

对于您的问题,这不是一个很好的答案。另外,我从未使用过 Doctrine 或 Doctrine2。但是我花了一些时间环顾四周,最终得到了前三个参考:

Doctrine multiple composite foreign key,一个问题,虽然它没有显示 XML 映射,并且可能是离题的,至少它看起来是关于 FK 中的多列。并回答根据答案忽略的 Doctrine2 的某些方面。

Doctrine2 使用复合外键映射实体...一个没有收集太多价值但至少可以作为欺骗候选人折叠到您的问题中的问题。

XML 映射Doctrine2 XML 映射文档。在文本上搜索没有任何价值,multi但在搜索上composite说:

对于复合键,您可以指定多个 id 元素,但是建议将代理键与 Doctrine 2 一起使用。

这让我想到了这个维基百科对代理的定义,它指出:

代理由系统内部生成,对用户或应用程序不可见。

自然对代理。讨论两者之间的选择。

回到您的模型,按独立性降序排列:

CREATE TABLE `groups` (
  `groupId` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `someMoreData` VARCHAR(32),
  PRIMARY KEY (`groupId`)
) ENGINE=InnoDB;

CREATE TABLE `domains` (
  `domainId` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `groupId` int(10) unsigned NOT NULL,
  `someOtherData` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`domainId`),
  KEY `key_domains_groupId` (`groupId`),
  CONSTRAINT `fk_domains_groups` FOREIGN KEY (`groupId`) REFERENCES `groups` (`groupId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `users` (
  `userId` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `groupId` int(10) unsigned NOT NULL,
  `domainId` int(10) unsigned NOT NULL,
  `someData` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`userId`),
  KEY `key_users_groupId_domainId` (`groupId`,`domainId`),
  CONSTRAINT `fk_users_domains` FOREIGN KEY (`groupId`, `domainId`) REFERENCES `domains` (`groupId`, `domainId`),
  CONSTRAINT `fk_users_groups` FOREIGN KEY (`groupId`) REFERENCES `groups` (`groupId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

一些临时工作:

truncate table groups; -- disallowed
delete from groups;
alter table groups auto_increment 1; -- reset, after running delete from.
insert groups(someMoreData) values ('group0001'),('group0002');
select * from groups;
insert domains(groupId,someOtherData) values 
(1,'sod'),(1,'sod'),(1,'sod'),
(2,'sod'),(2,'sod');
select * from domains; -- AI 1 to 5 above
insert users(groupId,domainId,someData) values (1,1,'sd'); -- success
insert users(groupId,domainId,someData) values (1,3,'sd'); -- success
insert users(groupId,domainId,someData) values (1,4,'sd'); -- Error 1452 fk failure

很明显,users并不真正需要复合 FK 到domains. 相反,它只需要一列 FK 进入domains. 这足以完成与您正在做的事情相同的效果。

与此一致,users.domainId就足够了,并users.groupId引入了非规范化,后者应该被丢弃。

无论如何,希望这会有所帮助。

于 2016-07-06T23:30:33.087 回答