Наследование таблиц классов Symfony / Doctrine и внешний ключ в качестве первичного ключа

#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). Но… отношения не передаются по наследству.

Надеюсь, это поможет…