DDC-3169: ManyToMany association fails when joining on a single column of a composity key #3927

Open
opened 2026-01-22 14:31:38 +01:00 by admin · 0 comments
Owner

Originally created by @doctrinebot on GitHub (Jun 17, 2014).

Originally assigned to: @beberlei on GitHub.

Jira issue originally created by user bramstroker:

I have two entities with a ManyToMany association between them. The first entity *Campsite* has a composite key (campsiteID, year). The second entity Region has a single key (regionID).
I want to create an association between *Campsite::campsiteID* and Region::regionID. See the entities below.

/****
 * @ORM\Table(name="Campsite")
 */
class Campsite
{
    /****
     * @ORM\Id
     * @ORM\Column(name="campsiteID", type="integer", precision=0, nullable=false)
     */
    protected $campsiteID;

    /****
     * @ORM\Id
     * @ORM\Column(name="year", type="smallint", precision=0, nullable=false)
     */
    protected $year;

    /****
     * @ORM\ManyToMany(targetEntity="AcsiGeo\Entity\Region", fetch="EAGER", cascade={"detach"})
     * @ORM\JoinTable(name="CampsiteRegion",
     *   joinColumns={
     *     @ORM\JoinColumn(name="campsiteID", referencedColumnName="campsiteID", nullable=false)
     *   },
     *   inverseJoinColumns={
     *     @ORM\JoinColumn(name="regionID", referencedColumnName="regionID", nullable=false)
     *   }
     * )
     * @var \Doctrine\Common\Collections\ArrayCollection $regions
     */
    protected $regions;
}
/****
 * @ORM\Table(name="Region")
 */
class Region
{
    /****
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     * @ORM\Column(name="regionID", type="integer", precision=0, nullable=false)
     */
    protected $regionID;
}

I run the following code to persist a new one.

$campsite = new Campsite();
$campsite->setCampsiteID(111111);
$campsite->setYear(2014);

$region = new Region();
$region->setRegionID(1);
$campsite->addRegion($region);

$em->persist($region);
$em->persist($campsite);
$em->flush();

This results in a record added to the CampsiteRegion table:

campsiteID : 2014
regionID: 1

This is clearly wrong as the value of the year field is added to the campsiteID column.

While debugging the problem I've found an issue with the method to determine the params in ManyToManyPersister on line 147.
The following code pops the last identifier from the array of identifiers.

$params[] = $isRelationToSource ? array*pop($identifier1) : array*pop($identifier2);

In my case:

array(
    'campsiteID' => 111111,
    'year' => 2014
)

Which picks 2014 as the value to use.
When I change the code to get the actual column from the array everything works as expected.

$params[] = $isRelationToSource ? $identifier1[$joinTableColumn] : $identifier2[$joinTableColumn];

I am not 100% sure if this change will have some side effects / edge case I'm not aware of.

For the time being I have fixed the problem bij just reversing the properties in my class, but this is not a real fix of course.

Originally created by @doctrinebot on GitHub (Jun 17, 2014). Originally assigned to: @beberlei on GitHub. Jira issue originally created by user bramstroker: I have two entities with a ManyToMany association between them. The first entity **Campsite\* has a composite key (_campsiteID_, _year_). The second entity _Region_ has a single key (*regionID**). I want to create an association between **Campsite::campsiteID\* and *Region::regionID**. See the entities below. ``` /**** * @ORM\Table(name="Campsite") */ class Campsite { /**** * @ORM\Id * @ORM\Column(name="campsiteID", type="integer", precision=0, nullable=false) */ protected $campsiteID; /**** * @ORM\Id * @ORM\Column(name="year", type="smallint", precision=0, nullable=false) */ protected $year; /**** * @ORM\ManyToMany(targetEntity="AcsiGeo\Entity\Region", fetch="EAGER", cascade={"detach"}) * @ORM\JoinTable(name="CampsiteRegion", * joinColumns={ * @ORM\JoinColumn(name="campsiteID", referencedColumnName="campsiteID", nullable=false) * }, * inverseJoinColumns={ * @ORM\JoinColumn(name="regionID", referencedColumnName="regionID", nullable=false) * } * ) * @var \Doctrine\Common\Collections\ArrayCollection $regions */ protected $regions; } ``` ``` /**** * @ORM\Table(name="Region") */ class Region { /**** * @ORM\Id * @ORM\GeneratedValue(strategy="IDENTITY") * @ORM\Column(name="regionID", type="integer", precision=0, nullable=false) */ protected $regionID; } ``` I run the following code to persist a new one. ``` $campsite = new Campsite(); $campsite->setCampsiteID(111111); $campsite->setYear(2014); $region = new Region(); $region->setRegionID(1); $campsite->addRegion($region); $em->persist($region); $em->persist($campsite); $em->flush(); ``` This results in a record added to the CampsiteRegion table: campsiteID : 2014 regionID: 1 This is clearly wrong as the value of the year field is added to the campsiteID column. While debugging the problem I've found an issue with the method to determine the params in **ManyToManyPersister** on line 147. The following code pops the last identifier from the array of identifiers. ``` $params[] = $isRelationToSource ? array*pop($identifier1) : array*pop($identifier2); ``` In my case: ``` array( 'campsiteID' => 111111, 'year' => 2014 ) ``` Which picks 2014 as the value to use. When I change the code to get the actual column from the array everything works as expected. ``` $params[] = $isRelationToSource ? $identifier1[$joinTableColumn] : $identifier2[$joinTableColumn]; ``` I am not 100% sure if this change will have some side effects / edge case I'm not aware of. For the time being I have fixed the problem bij just reversing the properties in my class, but this is not a real fix of course.
admin added the Bug label 2026-01-22 14:31:38 +01:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#3927