如何与 MappedSuperclass 作品建立联系?

kri*_*016 3 doctrine symfony symfony5

我在 Symfony 5 中对多对一与 MappedSuperclass 的关系有问题。我有实体 Employee、Employer ,它们扩展了 MappedSuperclass 抽象类 Person。我想创建与人员(雇员和雇主)相关的报告实体,如下所示:

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

Run Code Online (Sandbox Code Playgroud)

但是当我尝试推送迁移时,我收到以下错误消息:

从 App\Entity\Raport 到 App\Entity\Person 的关系引用的列名称id不存在。

但我在这些类中有 id 属性:

    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    protected $id;
Run Code Online (Sandbox Code Playgroud)

我在 Symfony 页面示例中找到了创建界面来执行此操作,但它对我来说也不起作用。也许有人以前遇到过这个问题并且知道如何解决它。非常感谢您的任何回复。

编辑我的人课程:

**
 * 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)

Run Code Online (Sandbox Code Playgroud)

现在,当我尝试立即创建 Employee 或 Employer 时,将其从超类更改为“JOINED”继承时,出现以下错误:

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        
Run Code Online (Sandbox Code Playgroud)

没有任何其他方法可以将一个属性与实现一个接口或扩展类的少数实体建立关系?有时我讨厌教义......而我的个人实体也许有助于配置错误:

* @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;
    }

}
Run Code Online (Sandbox Code Playgroud)

Jak*_*umi 5

您不能让关系以 MappedSuperClass 为目标,因为它本身不是实体。它本身只能定义一个拥有的一对一关系(或非常有限的多对多):

映射超类不能是实体,它不可查询,并且映射超类定义的持久关系必须是单向的(仅具有拥有方)。这意味着在映射的超类上根本不可能存在一对多关联。此外,只有当映射的超类当前仅在一个实体中使用时,多对多关联才有可能。为了进一步支持继承,必须使用单表或连接表继承功能。

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

可能想要的是单表继承或类表继承(请参阅上面的链接,它也显示了这些)。但它可能会变得很烦人。你已被警告过。


小智 5

可以与 MappedSuperClass(在 Symfony 中)建立关系。您想要的是动态映射,但该映射没有很好的文档记录。您必须使用Doctrine Event loadClassMetadata。文档示例非常(非常)简单,但是您可以做更多。

在您的情况下,您必须检查该实体是否是您想要的实体并且不是 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,
                ]]
            ));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
services:
    App\Doctrine\LoadClassMetadataListener
        tags:
            - { name: doctrine.event_subscriber }
Run Code Online (Sandbox Code Playgroud)

$metadata允许访问所有映射可能性和所有映射选项,例如注释、yaml 或 XML。