Как использовать Doctrine с двунаправленным наследованием один к одному - PullRequest
0 голосов
/ 14 мая 2019

У меня есть объект MainClass, который содержит другой объект SubClass, и я использую двунаправленный один-к-одному.Существует несколько версий SubClass, которые смоделированы с использованием наследования типов классов.ERD показано ниже.Обратите внимание, что если я делаю что-то не так или есть ошибка в Doctrine, но при добавлении записи Doctrine не предоставляет правильное количество параметров для запроса.enter image description here

Мои сущности определены следующим образом (SubClassType2 не релевантен и не показан)

<?php
use Doctrine\ORM\Mapping as ORM;

/**
 * MainClass
 *
 * @Table(name="mainClass")
 * @Entity
 */
class MainClass
{
    /**
     * @var int
     *
     * @Column(name="id", type="integer")
     * @Id
     * @GeneratedValue(strategy="IDENTITY")
     */
    protected $id;

    /** @Column(type="string") */
    protected $name;

    /**
     * @var \SubClass
     *
     * @OneToOne(targetEntity="SubClass", mappedBy="mainClass", cascade={"persist","remove"}, orphanRemoval=true)
     */
    protected $subClass;

    public function getId()
    {
        return $this->id;
    }

    public function getName()
    {
        return $this->name;
    }
    public function setName($name)
    {
        $this->name = $name;
    }

    public function setSubClass(\SubClass $subClass)
    {
        $this->subClass = $subClass;

        return $this;
    }

    public function getSubClass()
    {
        return $this->subClass;
    }
}

<?php
use Doctrine\ORM\Mapping as ORM;

/**
 * SubClass
 *
 * @Table(name="subClass")
 * @InheritanceType("JOINED")
 * @DiscriminatorColumn(name="discriminator", type="string", length=32)
 * @DiscriminatorMap({"subClassType1" = "SubClassType1", "subClassType2" = "SubClassType2"})
 * @Entity
 */
abstract class SubClass
{
    /**
     * @var \MainClass
     *
     * @Id
     * @GeneratedValue(strategy="NONE")
     * @OneToOne(targetEntity="MainClass", inversedBy="subClass")
     * @JoinColumns({
     *   @JoinColumn(name="id", referencedColumnName="id", onDelete="CASCADE")
     * })
     */
    protected $mainClass;

    /** @Column(type="string") */
    protected $someCommonProperty;


    public function setMainClass(\MainClass $mainClass)
    {
        $mainClass->setSubClass($this);
        $this->mainClass = $mainClass;

        return $this;
    }

    public function getMainClass()
    {
        return $this->mainClass;
    }

    public function getId()
    {
        return $this->id;
    }

    public function getSomeCommonProperty()
    {
        return $this->someCommonProperty;
    }
    public function setSomeCommonProperty($someCommonProperty)
    {
        $this->someCommonProperty = $someCommonProperty;
    }
}

<?php
use Doctrine\ORM\Mapping as ORM;

/**
 * SubClassType1
 *
 * @Table(name="subclassType1")
 * @Entity
 */
class SubClassType1 extends SubClass
{

    /** @Column(type="string") */
    protected $someIndividualProperty;

    public function getSomeIndividualProperty()
    {
        return $this->someIndividualProperty;
    }
    public function setSomeIndividualProperty($someIndividualProperty)
    {
        $this->someIndividualProperty = $someIndividualProperty;
    }
}

Я пытаюсь добавить новую запись следующим образом.

<?php
ini_set('display_errors', 1);

require_once "bootstrap.php";

$mainClass = new MainClass();
$mainClass->setName('MainClassName');
$subClass=new SubClassType1();
$subClass->setSomeCommonProperty('SomeCommonProperty');
$subClass->setSomeIndividualProperty('SomeIndividualProperty');
$subClass->setMainClass($mainClass);

$entityManager->getConnection()
  ->getConfiguration()
  ->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger())
;

$entityManager->persist($mainClass);
$entityManager->flush();

Вывод:

[michael@devserver testing]$ php create.php
"START TRANSACTION"
INSERT INTO mainClass (name) VALUES (?)
array(1) {
  [1]=>
  string(13) "MainClassName"
}
array(1) {
  [1]=>
  string(6) "string"
}
INSERT INTO subClass (someCommonProperty, id, discriminator) VALUES (?, ?, ?)
array(3) {
  [1]=>
  string(18) "SomeCommonProperty"
  [2]=>
  int(7)
  [3]=>
  string(13) "subClassType1"
}
array(3) {
  [1]=>
  string(6) "string"
  [2]=>
  string(7) "integer"
  [3]=>
  string(6) "string"
}

Notice: Undefined index: 000000000744ff62000000006b73da3c in /var/www/testing/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php on line 2995
INSERT INTO subclassType1 (id, someIndividualProperty) VALUES (?, ?)
array(1) {
  [1]=>
  string(22) "SomeIndividualProperty"
}
array(1) {
  [1]=>
  string(6) "string"
}
"ROLLBACK"

Fatal error: Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in /var/www/testing/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:117
Stack trace:
#0 /var/www/testing/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php(117): PDOStatement->execute(NULL)
#1 /var/www/testing/vendor/doctrine/dbal/lib/Doctrine/DBAL/Statement.php(153): Doctrine\DBAL\Driver\PDOStatement->execute(NULL)
#2 /var/www/testing/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php(213): Doctrine\DBAL\Statement->execute()
#3 /var/www/testing/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php(1073): Doctrine\ORM\Persisters\Entity\JoinedSubclassPersister->executeInserts()
#4 /var/www/testing/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php(386): Doctrine\ORM\UnitOfWork->executeInserts(Object(Doctrine\ORM\Mapping\ClassMetadata))
#5 /var/www/testing/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php(359): Do in /var/www/testing/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php on line 106
[michael@devserver testing]$

Как видно, подготовленное утверждение INSERT INTO subclassType1 (id, someIndividualProperty) VALUES (?, ?) передается array(1) {[1] => string(22) "SomeIndividualProperty"}.Возможно, вы заметили, что мои свойства защищены, а не частные, и это была всего лишь надежда, что это решит проблему, но не сделали этого.Я также экспериментировал с обратными вызовами жизненного цикла и обнаружил, что ошибка возникает между PostCersist MainClass и PostPersist SubClass, однако я не уверен, может ли это чем-то помочь.

Как можно создать новую запись?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...