Multiple Navigational Properties to the same entity with composite primary key #7220

Open
opened 2026-01-22 15:47:16 +01:00 by admin · 0 comments
Owner

Originally created by @theoaksoft on GitHub (Sep 12, 2023).

Bug Report

I have two entities EntA & EntB defined as follows:

<?php

#[ORM\Entity]
class EntA {
    #[ORM\Id]
    #[ORM\Column(length=10)]
    private string $id1;
    #[ORM\Id]
    #[ORM\Column(length=100)]
    private string $id2;

    public function __construct(string $id1, string $id2) {
        $this->id1 = $id1;
        $this->id2 = $id2;
    }
}

#[ORM\Entity]
class EntB {
    #[ORM\Id]
    #[ORM\Column(length=50)]
    private string $id;
    #[ORM\ManyToOne(targetEntity: EntA::class)]
    #[ORM\JoinColumn(name: "ref_id", referencedColumnName="id1")]
    #[ORM\JoinColumn(name: "ref_id2", referencedColumnName="id2")]
    private ?EntA $ref1 = null;
    #[ORM\ManyToOne(targetEntity: EntA::class)]
    #[ORM\JoinColumn(name: "ref_id", referencedColumnName="id1")]
    #[ORM\JoinColumn(name: "ref_id2", referencedColumnName="id2")]
    private ?EntA $ref2 = null;
    #[ORM\ManyToOne(targetEntity: EntA::class)]
    #[ORM\JoinColumn(name: "ref_id", referencedColumnName="id1")]
    #[ORM\JoinColumn(name: "ref_id3", referencedColumnName="id2", nullable=true)]
    private ?EntA $ref3 = null;

    public function __construct(EntA $ref1, EntA $ref2, ?EntA $ref3 = null) {
        $this->id = random_str();
        $this->ref1 = $ref1;
        $this->ref2 = $ref2;
        $this->ref3 = $ref3;
    }
}

The design is to ensure that all reference to EntA from EntB all belong under the same parent and by parent, I mean EntA::$id1.

Q A
BC Break no
Version 2.14.0

Summary

Whenever I instantiate EntB and set EntB::$ref3 to null, doctrine sets the column ref_id in the EntB table to null thereby making the other EntA references to be orphans. even though columns ref_id1, ref_id2 have their values intact while column ref_id3 is null as expected.

Current behavior

EntA Table
id1: ABC, id2: 123
id1: ABC, id2: 234 

EntB Table
id: aystetx, ref_id: null, ref_id1: 123, ref_id2: 234, ref_id3: null

How to reproduce

$ent_a_1 = new EntA("ABC", "123");
$entityManager->persist($ent_a_1);
$ent_a_2 = new EntA("ABC", "234");
$entityManager->persist($ent_a_2);

$ent_b = new EntB($ref_a_1, $ref_a_2);
$entityManager->persist($ent_b);

$entityManager->flush();

Expected behavior

EntA Table
id1: ABC, id2: 123
id1: ABC, id2: 234 

EntB Table
id: aystetx, ref_id: ABC, ref_id1: 123, ref_id2: 234, ref_id3: null
Originally created by @theoaksoft on GitHub (Sep 12, 2023). ### Bug Report I have two entities `EntA` & `EntB` defined as follows: ``` <?php #[ORM\Entity] class EntA { #[ORM\Id] #[ORM\Column(length=10)] private string $id1; #[ORM\Id] #[ORM\Column(length=100)] private string $id2; public function __construct(string $id1, string $id2) { $this->id1 = $id1; $this->id2 = $id2; } } #[ORM\Entity] class EntB { #[ORM\Id] #[ORM\Column(length=50)] private string $id; #[ORM\ManyToOne(targetEntity: EntA::class)] #[ORM\JoinColumn(name: "ref_id", referencedColumnName="id1")] #[ORM\JoinColumn(name: "ref_id2", referencedColumnName="id2")] private ?EntA $ref1 = null; #[ORM\ManyToOne(targetEntity: EntA::class)] #[ORM\JoinColumn(name: "ref_id", referencedColumnName="id1")] #[ORM\JoinColumn(name: "ref_id2", referencedColumnName="id2")] private ?EntA $ref2 = null; #[ORM\ManyToOne(targetEntity: EntA::class)] #[ORM\JoinColumn(name: "ref_id", referencedColumnName="id1")] #[ORM\JoinColumn(name: "ref_id3", referencedColumnName="id2", nullable=true)] private ?EntA $ref3 = null; public function __construct(EntA $ref1, EntA $ref2, ?EntA $ref3 = null) { $this->id = random_str(); $this->ref1 = $ref1; $this->ref2 = $ref2; $this->ref3 = $ref3; } } ``` The design is to ensure that all reference to `EntA` from `EntB` all belong under the same parent and by parent, I mean `EntA::$id1`. | Q | A |------------ | ------ | BC Break | no | Version | 2.14.0 #### Summary Whenever I instantiate `EntB` and set `EntB::$ref3` to null, doctrine sets the column `ref_id` in the `EntB` table to null thereby making the other `EntA` references to be orphans. even though columns `ref_id1`, `ref_id2` have their values intact while column `ref_id3` is null as expected. #### Current behavior ``` EntA Table id1: ABC, id2: 123 id1: ABC, id2: 234 EntB Table id: aystetx, ref_id: null, ref_id1: 123, ref_id2: 234, ref_id3: null ``` #### How to reproduce ``` $ent_a_1 = new EntA("ABC", "123"); $entityManager->persist($ent_a_1); $ent_a_2 = new EntA("ABC", "234"); $entityManager->persist($ent_a_2); $ent_b = new EntB($ref_a_1, $ref_a_2); $entityManager->persist($ent_b); $entityManager->flush(); ``` #### Expected behavior ``` EntA Table id1: ABC, id2: 123 id1: ABC, id2: 234 EntB Table id: aystetx, ref_id: ABC, ref_id1: 123, ref_id2: 234, ref_id3: null ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#7220