У нас есть схема базы данных, которая в упрощенной (слегка надуманной) форме выглядит так:
Если внешний ключ от пользователей до доменов установлен в столбцах (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`);
Это не фантастический ответ на ваш вопрос. Кроме того, я никогда не использовал Doctrine или Doctrine2. Но я провел некоторое время, оглядываясь по сторонам, и в значительной степени оказался в этих первых трех ссылках:
Doctrine множественный составной внешний ключ , вопрос, хотя он не отображает XML-сопоставления и может быть вне базы, по крайней мере, это похоже на несколько столбцов в FK. И ответьте на некоторые аспекты Doctrine2, которые игнорируются в соответствии с ответом.
Doctrine2 Создавайте объекты с составными внешними ключами в … Вопрос, который не получил большого значения, но может быть сложен в ваш вопрос как минимум.
XML-сопоставление Документация XML-документации Doctrine2. Это не имеет никакого значения при поиске в текстовом 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 в суррогатном AI PK domains
. Это достаточно и достаточно плотно, чтобы добиться того же эффекта, что и вы.
В соответствии с этим, users.domainId
достаточно, и users.groupId
вводит денормализацию, а последний должен быть отброшен.
В любом случае, надеюсь, это поможет.