Как сделать связь с MappedSuperclass работает? - PullRequest
0 голосов
/ 25 мая 2020

У меня проблема с отношением Many к One к MappedSuperclass в Symfony 5. У меня есть сущности Employee, Employer, которые расширяют абстрактный класс MappedSuperclass Person. И я хочу создать объект raports, который будет связан с человеком (как сотрудником, так и работодателем), как показано ниже:

    /**
     * @ORM\ManyToOne(targetEntity=Person::class)
     */
    private $person;

Но когда я пытаюсь выполнить миграцию pu sh, я получаю следующее сообщение об ошибке:

Имя столбца id, на которое ссылается отношение из App \ Entity \ Raport к App \ Entity \ Person, не существует.

, но у меня есть свойства id в этих классах:

    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    protected $id;

Я нашел на странице Symfony пример создания интерфейса для этого, но у меня он тоже не работает. Может, у кого-то была такая проблема раньше и он знает, как ее решить. Большое спасибо за любой ответ.

EDIT My Person class:

**
 * Abstract base class to be extended by my entity classes with same fields
 *
 * @MappedSuperclass
 */
abstract class Person
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    protected $id; //This property exist in Employee and Employer too (like doctrine documentation said)

Теперь, когда я меняю его с суперкласса на наследование «JOINED», когда я пытаюсь создать сейчас Employee или Employer, я получаю следующее error:

An exception occurred while executing 'INSERT INTO person (discr) VALUES  
   (?)' with params ["Employee"]:                                                  

  SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error i  
  n your SQL syntax; check the manual that corresponds to your MySQL server v  
  ersion for the right syntax to use near 'person (discr) VALUES ('Employee')'  
   at line 1        

Нет другого способа просто установить связь в одном свойстве с несколькими объектами, которые реализуют один интерфейс или расширяют класс ?? Иногда я ненавижу doctrine ... И мое физическое лицо, возможно, помогает настроить, что не так:

* @ORM\Entity(repositoryClass=PersonRepository::class)
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 * @ORM\DiscriminatorMap({"person" = "Person", "employee" = "Employee", "employer" = "Employer"})
 */
class Person
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    protected $id;

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

}

Ответы [ 3 ]

2 голосов
/ 26 мая 2020

У вас не может быть отношения, нацеленного на MappedSuperClass, поскольку оно НЕ является самой сущностью. Он может только сам определять отношение «один-к-одному» (или очень ограниченное «многие-ко-многим»):

Отображенный суперкласс не может быть сущностью, он не поддерживает запросы и постоянные отношения определенный отображаемым суперклассом должен быть однонаправленным (только со стороной-владельцем). Это означает, что ассоциации "один ко многим" вообще невозможны в отображенном суперклассе. Более того, ассоциации "многие-ко-многим" возможны только в том случае, если отображаемый суперкласс в данный момент используется только в одной сущности. Для дальнейшей поддержки наследования должны использоваться функции наследования одиночной или объединенной таблицы.

source: https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/inheritance-mapping.html#mapped -superclasses

What you might want - это наследование одной таблицы или наследования таблицы классов (см. ссылку выше, она также показывает их). Однако это может сильно раздражать. Вас предупредили.

0 голосов
/ 27 августа 2020

Возможно иметь отношения в MappedSuperClass (в Symfony). Вам нужно отображение динамического c, которое плохо документировано. Вы должны использовать Doctrine Event loadClassMetadata . Пример do c очень (очень) прост, но вы можете сделать и больше.

В вашем случае вы должны проверить, является ли сущность той, которую вы хотите, и не является ли она MappedSuperClass:

<?php

namespace App\Doctrine;

use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Events;

class LoadClassMetadataListener implements EventSubscriber
{
    public function getSubscribedEvents()
    {
        return [
            Events::loadClassMetadata,
        ];
    }

    public function loadClassMetadata(\Doctrine\ORM\Event\LoadClassMetadataEventArgs $eventArgs)
    {
        $metadata = $eventArgs->getClassMetadata();
        $class = new \ReflectionClass($metadata->getName());

        if ($class->implementsInterface('Your\Interface') && !$metadata->isMappedSuperclass) {
            $metadata->mapManyToOne(array(
                'targetEntity'  => Person::class,
                'fieldName'     => 'person',
                'inversedBy'    => 'whatYouWant',
                'joinColumns'   => [[
                    'name'                 => 'xxx_id',
                    'referencedColumnName' => 'id',
                    'nullable'             => false,
                ]]
            ));
        }
    }
}
services:
    App\Doctrine\LoadClassMetadataListener
        tags:
            - { name: doctrine.event_subscriber }

$metadata дает доступ ко всем возможностям сопоставления и всем параметрам сопоставления, например с аннотациями, yaml или XML.

0 голосов
/ 25 мая 2020

Попробуйте удалить аннотацию . У меня нет отношения MappedSuperclass. Я установил MappedSuperclass как абстрактный для класса в проекте и получаю сообщение об ошибке. Абстрактный класс кажется недопустимым. Это также имеет смысл, потому что это не абстрактный класс в этом смысле.

...