Php 在ORM 2中加入类表继承时“主键elementId缺少值”
当我试图加入一个继承的类时,我从理论中得到一个OutOfBoundsException,上面有错误消息 我定义了以下实体: FormElement是父类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",
/**
* @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;
}