简体   繁体   中英

“Missing value for primary key elementId” when joining on Class Table Inheritance in Doctrine ORM 2

When I try to join on an inherited class I get an OutOfBoundsException from Doctrine with the error message above.

I have defined following entities:

FormElement is the parent class

/**
 * @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 is a child class

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

And Choice joins on 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 is a FormElement and has multiple Choice s. Everything works fine, even the call to ChoiceElement::getChoices() . When I try to access the resulting ArrayCollection however, Doctrine throws error mentioned above. I already did some digging using the debugger, but I don't understand if this is a bug or intended behaviour.

I really hope someone can help me here.

Since ChoiceElement inherits Formelement , it does not need to have another id field.

As it is, when doctrine stumbles upon your ChoiceElement entity, it will define a composite primary key because two fields are marked with the @ORM\\Id annotation which is probably not the behaviour you want. Thus, when it tries to join from your Choice entity, Doctrine complains because it only has one of the two needed keys that compose the primary key.

To solve this, simply remove the id attribute of your ChoiceElement entity. Consequently, don't forget to update the referencedColumnName attribute of your choiceElement association. It should now be ELE_ID and not CHOE_ID .


Edit: Quick working example:

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

Outputs the following schema:

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

And when I am trying to browse the array collection of B entities from an A entity, Doctrine triggers the following query successfully:

SELECT t0.id AS id_1, t0.a_id AS a_id_2 FROM b t0 WHERE t0.a_id = ?

In the same fashion, it is able to join the B table without a fuss if I ask it to. Here is the query performed when I join 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 = ?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM