"缺少主键elementId"在Doctrine ORM 2中加入类表继承时

时间:2018-01-31 15:40:54

标签: php inheritance doctrine-orm orm doctrine

当我尝试加入一个继承的类时,我从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;
}

ChoiceElementFormElement,有多个Choice。一切正常,甚至拨打ChoiceElement::getChoices()。但是,当我尝试访问生成的ArrayCollection时,Doctrine会抛出上面提到的错误。 我已经使用调试器进行了一些挖掘,但我不明白这是一个错误还是预期的行为。

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

1 个答案:

答案 0 :(得分:0)

由于ChoiceElement继承了Formelement,因此不需要另外的id字段。

实际上,当教义偶然发现你的ChoiceElement实体时,它会定义一个复合主键,因为两个字段都标有@ORM\Id注释,这可能不是你想要的行为。因此,当它尝试从您的Choice实体加入时,Doctrine会抱怨,因为它只有构成主键的两个必需键之一。

要解决此问题,只需删除id实体的ChoiceElement属性即可。因此,请勿忘记更新referencedColumnName关联的choiceElement属性。它现在应该是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);

当我尝试从B实体浏览A个实体的数组时,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 = ?