如何在学义映射中描述多列外键

Jac*_*cco 5 php mysql doctrine foreign-key-relationship doctrine-mapping

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

在此处输入图片说明

在列(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>
Run Code Online (Sandbox Code Playgroud)

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

所以,我的问题是:

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



为了完整起见,数据库为上述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`);
Run Code Online (Sandbox Code Playgroud)

Dre*_*rew 3

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

教义多重复合外键,一个问题,尽管它没有显示 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;
Run Code Online (Sandbox Code Playgroud)

一些临时工作:

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
Run Code Online (Sandbox Code Playgroud)

很明显,users并不真正需要复合 FK 到 中domains。相反,它只需要将单列 FK 放入 的替代 AI PK 中domains。这足以达到与您正在做的相同的效果。

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

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