Damien
Damien

Reputation: 5882

How to deal with association on composite key entities with Doctrine2?

Say I have an Offer, which can have 1-n Range. Immediately you think, "put a offer_id inside Range".

But my Offer has a composite primary key (composed of two fields). There is no AUTOINCREMENT id column.

The Doctrine2 documentation doesn't say much about that particular case, here is my entities:

<?php
use Doctrine\ORM\Mapping as ORM;
/**
 * @ORM\Table()
 * @ORM\Entity
 */
class Offer
{
    /**
     * @var Site $site
     * @ORM\Id
     * @ORM\ManyToOne(targetEntity="Site")
     * @ORM\JoinColumn(name="site_id", referencedColumnName="id")
     */
        private $site;

    /**
     * @var string $pouet
     * @ORM\Id
     * @ORM\Column(name="pouet", type="string", length=255)
     */
    private $pouet;
}

<?php
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(name="RangeItem")
 * @ORM\Entity
 */
class Range
{
    /**
     * @todo This is test code only do not push me :-)
     * @var ArrayCollection
     * @ORM\ManyToOne(targetEntity="Offer")
     */
    private $offers;
}

I obtaind this error:

[Doctrine\ORM\ORMException]
Column name id referenced for relation from Pouet\MyBundle\Entity\Range towards Pouet\MyBundle\Entity\Offer does not exist.

That make sense, but how can I deal with this issue? Is a Table with composite primary key forbidden to have associations on it?

Upvotes: 10

Views: 14422

Answers (2)

Kenny Body
Kenny Body

Reputation: 1149

I believe the solution is to mirror the primary key (PK) for the foreign key (FK). I.E. for each column that makes up the PK (site, pouet) you need to have the same columns on the related entity.

You can do this by using the JoinColumns annotation (or the equivalent in YAML/XML) with a JoinColumn for each part of the composite FK:

/**
 * @ORM\Table(name="RangeItem")
 * @ORM\Entity
 */
class Range
{
    /**
     * @todo This is test code only do not push me :-)
     * @var ArrayCollection
     * @ORM\ManyToOne(targetEntity="Offer")
     * @ORM\JoinColumns(
     *     @ORM\JoinColumn(name="site_id", referencedColumnName="site_id"),
     *     @ORM\JoinColumn(name="pouet", referencedColumnName="pouet")
     * )
     */
    private $offers;
}

I hope this might help somebody who is still struggling with this issue.

Upvotes: 9

Problematic
Problematic

Reputation: 17678

You should be able to use a @JoinColumn annotation in the Range class to specify which Id to use:

/**
 * @ORM\ManyToOne(targetEntity="Offer")
 * @ORM\JoinColumn(name="offer_pouet", referencedColumnName="pouet")
 */
private $offers;

Because the defaults for @JoinColumn, if you do not specify them, would be offer_id and id, respectively, you need to manually specify (I'm making a bit of an assumption here that pouet is a unique value for your Offer class).

EDIT: based on your comment, I found a tutorial on the Doctrine Project site for Composite Primary Key. The entity relationship has mappedBy for one key and indexBy for the other. Hope that helps.

Upvotes: 1

Related Questions