Php 在ORM 2中加入类表继承时“主键elementId缺少值”

Php 在ORM 2中加入类表继承时“主键elementId缺少值”,php,inheritance,doctrine-orm,orm,doctrine,Php,Inheritance,Doctrine Orm,Orm,Doctrine,当我试图加入一个继承的类时,我从理论中得到一个OutOfBoundsException,上面有错误消息 我定义了以下实体: FormElement是父类 /** * @ORM\Entity() * @ORM\InheritanceType("JOINED") * @ORM\DiscriminatorColumn(name="ETYP_ID", type="integer") * @ORM\DiscriminatorMap({ * 1 = "DatetimeElement",

当我试图加入一个继承的类时,我从理论中得到一个OutOfBoundsException,上面有错误消息

我定义了以下实体:

FormElement是父类

/**
 * @ORM\Entity()
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="ETYP_ID", type="integer")
 * @ORM\DiscriminatorMap({
 *     1 = "DatetimeElement",
 *     3 = "ChoiceElement",
 *     4 = "TextElement",
 *     5 = "MatrixElement",
 *     6 = "HtmlElement"
 *     })
 * @Table(name="FORMELEMENT")
 */
abstract class Formelement {
    /**
     * @var integer
     * @ORM\Id()
     * @ORM\Column(name="ELE_ID", type="integer", nullable=false)
     */
    private $elementId;
}
ChoiceElement是一个子类

/**
 * @ORM\Entity()
 * @ORM\Table(name="CHOICEELEMENT")
 */
class ChoiceElement extends Formelement {
    /**
     * @var integer
     * @ORM\Id()
     * @ORM\Column(name="CHOE_ID", type="integer", nullable=false)
     */
    private $id;
    /**
     * @var Choice[]|ArrayCollection
     * @ORM\OneToMany(targetEntity="Choice", mappedBy="choiceElement")
     */
    private $choices;

    public function getChoices(){
        return $this->choices;
    }
}
和Choice在ChoiceElement上联接

/**
 * Class Choice
 * @package apps\dynfrm\models\Doctrine\entities
 * @ORM\Entity()
 * @ORM\Table(name="CHOICE")
 */
class Choice {
    /**
     * @var integer
     * @ORM\Id()
     * @ORM\Column(name="CHO_ID", type="integer", nullable=false)
     */
    private $id;

    /**
     * @var ChoiceElement
     * @ORM\ManyToOne(targetEntity="ChoiceElement", inversedBy="choices")
     * @ORM\JoinColumn(name="CHOE_ID", referencedColumnName="CHOE_ID", nullable=false)
     */
    private $choiceElement;
}
ChoiceElement是一个FormElement,具有多个选项。一切正常,甚至调用ChoiceElement::getChoices。但是,当我尝试访问结果ArrayCollection时,Doctrine抛出上述错误。 我已经使用调试器进行了一些挖掘,但我不知道这是一个bug还是一种预期行为

我真的希望有人能在这里帮助我。

由于ChoiceElement继承了Formelement,所以它不需要另一个id字段

实际上,当doctrine偶然发现您的ChoiceElement实体时,它将定义一个复合主键,因为两个字段用@ORM\Id注释标记,这可能不是您想要的行为。因此,当它试图从您的选择实体加入时,Doctrine会抱怨,因为它只有组成主键的两个所需键中的一个

要解决这个问题,只需删除ChoiceElement实体的id属性。因此,不要忘记更新choiceElement关联的referencedColumnName属性。现在应该是ELE_ID而不是CHOE_ID

编辑:快速工作示例:

AbstractA.php

A.php

B.php

输出以下架构:

创建表抽象\u a id INT AUTO\u INCREMENT NOT NULL,discr INT NOT NULL,主键id默认字符集utf8 COLLATE utf8\u unicode\u ci ENGINE=InnoDB; 创建表a id INT NOT NULL,主键id默认字符集utf8 COLLATE utf8\U unicode\U ci ENGINE=InnoDB; 创建表b id INT AUTO_INCREMENT NOT NULL,a_id INT DEFAULT NULL,索引IDX_71BEEFF93BDE5358 a_id,主键id默认字符集utf8 COLLATE utf8\u unicode\u ci ENGINE=InnoDB; ALTER TABLE a ADD CONSTRAINT FK_E8B7BE43BF396750外键id引用DELETE级联上的抽象id; 更改表b添加约束FK_71BEEF93BDE5358外键a_id引用a id; 当我试图从A实体浏览B实体的数组集合时,Doctrine成功触发以下查询:

从b t0中选择t0.id作为id_1,选择t0.a_id作为a_id_2,其中t0.a_id=? 同样,如果我要求它加入B表,它也可以毫不费事地加入B表。以下是我加入a.bs时执行的查询:

选择a0.id作为id\u 0,b1.id作为id\u 1,a0.discr作为discr\u 2,b1.a\u id作为id\u 3 从一个a2_ a2_u.id=a0_u.id上的内部联接抽象 a2上的内部连接b1\uID=b1\uID 其中a0_u0.id=?
不幸的是,这也不起作用。因为在我的模式中,FORMELEMENT和CHOICEELEMENT是不同的表,ELE_ID是FORMELEMENT的主键,CHOE_ID是CHOICEELEMENT的主键,所以这些键是不同的。如果我尝试在ELE_ID上加入CHOE_ID,我不会得到任何结果。仅仅删除Choiceelement上的@Id注释也不起作用,我仍然会收到相同的错误消息。这很奇怪,我的一个项目中有一个非常类似的情况,它工作正常。我说的不是删除@Id注释,而是从ChoiceElement中删除整个$Id属性。在模式中是否有两个不同的表并不重要。Doctrine足够聪明,可以在子表中重复抽象类中定义的主键。这就是联合战略的运作方式。你到底尝试了什么?@lioxo我添加了一个对我有用的最小示例,希望能有所帮助。谢谢,你的示例帮助很大!不幸的是,它仍然不完全是我想要它做什么。我照你说的做了,从ChoiceElement中删除了$id属性,并将选项中的referencedColumnName设置为ELE_id。它现在不会抛出错误,但也不会返回任何给定ChoiceElement的任何选项。@lioxo正在执行哪种查询?
/**
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="discr", type="integer")
 * @ORM\DiscriminatorMap({1 = "A"})
 */
abstract class AbstractA
{

    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
}
/** @ORM\Entity() */
class A extends AbstractA
{
    /**
     * @ORM\OneToMany(targetEntity="B", mappedBy="a")
     */
    private $bs;
}
/** @ORM\Entity() */
class B
{
    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="A", inversedBy="bs")
     */
    private $a;
}