#php #symfony #inheritance #doctrine-orm #shared-primary-key
#php #symfony #наследование #doctrine-orm #общий-первичный-ключ
Вопрос:
В настоящее время я разрабатываю веб-приложение с Symfony 2.5 (и Doctrine 2.4.2), которое должно быть гибким, чтобы легко подключать новые модули / пакеты.
Итак, у меня есть объект (скажем, A), который имеет две взаимно однозначные ассоциации с абстрактными классами (B и C). Будущие модули будут реализовывать один из двух абстрактных классов. Поскольку ассоциации взаимно однозначны, я сделал их идентификаторами абстрактных классов, чтобы упростить доступ к ним, когда мы знаем идентификатор экземпляра
Итак, вот как выглядит код:
класс A:
<?php
namespace MeTestBundleEntity;
use DoctrineORMMapping as ORM;
/**
* @ORMTable()
* @ORMEntity
*/
class A
{
/**
* @ORMColumn(name="id", type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORMOneToOne(targetEntity="B", cascade={"all"}, mappedBy="a")
* @ORMJoinColumn(name="id", referencedColumnName="a_id")
*/
private $b;
/**
* @ORMOneToOne(targetEntity="C", cascade={"all"}, mappedBy="a")
* @ORMJoinColumn(name="id", referencedColumnName="a_id")
*/
private $c;
}
класс B:
<?php
namespace MeTestBundleEntity;
use DoctrineORMMapping as ORM;
/**
* @ORMTable()
* @ORMEntity
* @ORMInheritanceType("JOINED")
* @ORMDiscriminatorColumn(name="discr", type="string")
*/
abstract class B
{
/**
* @ORMId
* @ORMOneToOne(targetEntity="A", inversedBy="b")
* @ORMJoinColumn(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. Даже с учетом этих изменений моя схема остается действительной, и все та же ошибка по-прежнему возникает.
EDIT2: Если я создам другое поле в 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 будет игнорировать @ORDId, если вы не добавите определения InheritanceType. Когда вы добавите это определение InheritanceType, Doctrine сделает атрибут ‘a’ первичным ключом B. Также он создаст еще один атрибут с именем ‘a_id’, который будет служить внешним ключом для будущих подклассов (расширений B). Но… отношения не передаются по наследству.
Надеюсь, это поможет…