Наследование таблиц классов Symfony/Doctrine и внешний ключ как первичный ключ
В настоящее время я разрабатываю веб-приложение с Symfony 2.5 (и Doctrine 2.4.2), которое должно быть гибким, чтобы легко подключать новые модули / пакеты.
Итак, у меня есть сущность (скажем, A), которая имеет две однозначные ассоциации с абстрактными классами (B и C). Будущие модули будут реализовывать один из двух абстрактных классов. Поскольку ассоциации являются однозначными, я сделал их идентификаторами абстрактных классов, чтобы упростить доступ к ним, когда мы знаем идентификатор экземпляра A
Вот как выглядит код:
класс А:
<?php
namespace Me\TestBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table()
* @ORM\Entity
*/
class A
{
/**
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\OneToOne(targetEntity="B", cascade={"all"}, mappedBy="a")
* @ORM\JoinColumn(name="id", referencedColumnName="a_id")
*/
private $b;
/**
* @ORM\OneToOne(targetEntity="C", cascade={"all"}, mappedBy="a")
* @ORM\JoinColumn(name="id", referencedColumnName="a_id")
*/
private $c;
}
класс B:
<?php
namespace Me\TestBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table()
* @ORM\Entity
* @ORM\InheritanceType("JOINED")
* @ORM\DiscriminatorColumn(name="discr", type="string")
*/
abstract class B
{
/**
* @ORM\Id
* @ORM\OneToOne(targetEntity="A", inversedBy="b")
* @ORM\JoinColumn(name="a_id", referencedColumnName="id")
*/
private $a;
}
Я не буду публиковать код класса C, так как он такой же, как класс B.
На мой взгляд, вроде бы все хорошо. Даже для команды проверки соответствия. Действительно, когда я выполняю php app/console doctrine:schema:validate
, он говорит мне, что моя схема действительна. Однако эта команда затем пытается сравнить мою схему со схемой в базе данных, и в этот момент она просто не работает. php app/console doctrine:schema:update --dump-sql
терпит неудачу точно так же. Так что это довольно неловко, так как говорит мне, что моя схема действительна, но она не может использовать ее должным образом.
Ошибка:
[ErrorException]
Предупреждение: array_keys() ожидает, что параметр 1 будет массивом, значение NULL указано в /vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Index.php строке 95
Ошибка появляется, как только я добавляю аннотации InheritanceType и DiscriminatorColumn к классам B и C. Дело в том, что она говорит мне, что моя схема действительна.
Так кто-нибудь знает, если я делаю что-то не так? Или это определенно ошибка в Doctrine? Есть ли у вас какие-либо идеи, которые бы принесли как минимум такую же гибкость, как мое текущее решение?
Elioty
РЕДАКТИРОВАТЬ: я изменил сторону владения, чтобы быть абстрактными классами B и C, так как, в соответствии с документом, сторона владения - это сторона с внешним ключом и должна использовать атрибут inversedBy. Даже с этими изменениями моя схема все еще действительна, и та же самая ошибка все еще происходит.
РЕДАКТИРОВАТЬ 2: Если я создаю другое поле в B (и C) для хранения идентификатора сущности вместо взаимно-однозначного сопоставления, ошибка исчезает, но она больше не похожа на мою действительную схему.
РЕДАКТИРОВАТЬ 3: Я поговорил с членом команды разработчиков Doctrine, и он (и) сказал, что это определенно похоже на ошибку. Сообщить об ошибке здесь.
1 ответ
Прежде всего, команда php app/console doctrine:schema:validate
проверяет правильность текущей схемы. Текущая схема - это схема, сгенерированная вашей последней вызванной командой php app/console doctrine:schema:update --force
С другой стороны, команда php app/console doctrine:schema:update --dump-sql
не выполняет фактическое обновление схемы, хотя могут обнаруживаться некоторые ошибки, другие не будут появляться...
Я не понимаю класс B. Идентификационные данные этого (абстрактного) класса являются отношениями OneToOne? В любом случае, дело в том, что Doctine будет игнорировать @ORD\Id, если вы не добавите определенияиратский тип. Когда вы добавляете это определение в формате garitanceType, Doctrine сделает атрибут "a" первичным ключом B. Также он создаст еще один атрибут с именем "a_id", который будет служить внешним ключом для будущих подклассов (расширений B). Но... отношения не наследуются.
Надеюсь это поможет...