在 Doctrine ORM 2 中加入类表继承时出现“主键 elementId 的缺失值”
Posted
技术标签:
【中文标题】在 Doctrine ORM 2 中加入类表继承时出现“主键 elementId 的缺失值”【英文标题】:"Missing value for primary key elementId" when joining on Class Table Inheritance in Doctrine ORM 2 【发布时间】:2018-01-31 15:40:54 【问题描述】:当我尝试加入继承的类时,我从 Doctrine 收到 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
并且有多个Choice
s。一切正常,即使是对ChoiceElement::getChoices()
的调用。但是,当我尝试访问生成的 ArrayCollection
时,Doctrine 会抛出上述错误。
我已经使用调试器进行了一些挖掘,但我不明白这是一个错误还是预期的行为。
我真的希望有人可以在这里帮助我。
【问题讨论】:
【参考方案1】:由于ChoiceElement
继承了Formelement
,所以不需要另外有id字段。
事实上,当学说偶然发现您的ChoiceElement
实体时,它将定义一个复合主键,因为两个字段都标有@ORM\Id
注释,这可能不是您想要的行为。因此,当它尝试从您的 Choice
实体加入时,Doctrine 会抱怨,因为它只有组成主键的两个必需键之一。
要解决此问题,只需删除 ChoiceElement
实体的 id
属性即可。因此,不要忘记更新choiceElement
关联的referencedColumnName
属性。现在应该是ELE_ID
而不是CHOE_ID
。
编辑:快速工作示例:
AbstractA.php
/**
* @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;
A.php
/** @ORM\Entity() */
class A extends AbstractA
/**
* @ORM\OneToMany(targetEntity="B", mappedBy="a")
*/
private $bs;
B.php
/** @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;
输出以下架构:
CREATE TABLE abstract_a (id INT AUTO_INCREMENT NOT NULL, discr INT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
CREATE TABLE a (id INT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
CREATE TABLE b (id INT AUTO_INCREMENT NOT NULL, a_id INT DEFAULT NULL, INDEX IDX_71BEEFF93BDE5358 (a_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
ALTER TABLE a ADD CONSTRAINT FK_E8B7BE43BF396750 FOREIGN KEY (id) REFERENCES abstract_a (id) ON DELETE CASCADE;
ALTER TABLE b ADD CONSTRAINT FK_71BEEFF93BDE5358 FOREIGN KEY (a_id) REFERENCES a (id);
当我尝试从A
实体浏览B
实体的数组集合时,Doctrine 成功触发了以下查询:
SELECT t0.id AS id_1, t0.a_id AS a_id_2 FROM b t0 WHERE t0.a_id = ?
以同样的方式,如果我要求它加入B
表,它也不会大惊小怪。这是我加入a.bs
时执行的查询:
SELECT a0_.id AS id_0, b1_.id AS id_1, a0_.discr AS discr_2, b1_.a_id AS a_id_3
FROM a a2_
INNER JOIN abstract_a a0_ ON a2_.id = a0_.id
INNER JOIN b b1_ ON a2_.id = b1_.a_id
WHERE a0_.id = ?
【讨论】:
不幸的是,这也不起作用。因为在我的架构中,FORMELEMENT
和CHOICEELEMENT
是不同的表,ELE_ID
是FORMELEMENT
的主键,CHOE_ID
是CHOICEELEMENT
的主键,所以这些键是不同的。如果我尝试在ELE_ID
上加入CHOE_ID
,我不会得到任何结果。仅删除 Choiceelement 上的 @Id 注释也不起作用,我仍然收到相同的错误消息。
这很奇怪,我的一个项目中有一个非常相似的案例,它工作正常。我说的不是删除@Id
注释,而是从ChoiceElement
中删除整个$id
属性。在您的架构中是否有两个不同的表并不重要。 Doctrine 足够聪明,可以在子表中重复抽象类中定义的主键。这就是JOINED
策略的作用。你到底尝试了什么?
@lioxo 我添加了一个对我有用的最小示例,希望它可以提供帮助。
谢谢,你的例子帮了大忙!不幸的是,它仍然不是我想要的。我按照你说的做了,从 ChoiceElement 中删除了$id
-Attribute,并将 Choice 中的referencedColumnName
设置为ELE_ID
。它现在不会抛出错误,但对于任何给定的ChoiceElement
,它也不会返回任何Choice
s。
@lioxo 你在执行什么样的查询?以上是关于在 Doctrine ORM 2 中加入类表继承时出现“主键 elementId 的缺失值”的主要内容,如果未能解决你的问题,请参考以下文章