Search code examples
phpsymfonydoctrine-ormdoctrinepersist

Symfony Doctrine One to Many does not insert foreign key


I am having annoying problems with persisting an entity with one or more OneToMany-Childs.

I have a "Buchung" entity which can have multiple "Einsatztage" (could be translated to an event with many days)

In the "Buchung entity I have

/**
 * @param \Doctrine\Common\Collections\Collection $property
 * @ORM\OneToMany(targetEntity="Einsatztag", mappedBy="buchung", cascade={"all"})
 */
private $einsatztage;

$einsatztage is set to an ArrayCollection() in the __constructor().

Then there is the "Einsatztag" Entity which has a $Buchung_id variable to reference the "Buchung"

/**
 * @ORM\ManyToOne(targetEntity="Buchung", inversedBy="einsatztage", cascade={"all"})
 * @ORM\JoinColumn(name="buchung_id", referencedColumnName="id")
 */
private $Buchung_id;

Now If I try to persist an object to the database the foreign key of the "Einsatztag" Table is always left empty.

$buchung = new Buchung();

$buchung->setEvent(         $r->request->get("event_basis"));
$buchung->setStartDate(new \DateTime($r->request->get("date_from")));
$buchung->setEndDate(new \DateTime($r->request->get("date_to")));


$von = $r->request->get("einsatz_von");
$bis = $r->request->get("einsatz_bis");
$i = 0;
foreach($von as $tag){
    $einsatztag = new Einsatztag();

    $einsatztag->setNum($i);
    $einsatztag->setVon($von[$i]);
    $einsatztag->setBis($bis[$i]);

    $buchung->addEinsatztage($einsatztag);
    $i++;
}

$em = $this->getDoctrine()->getManager();

$em->persist($buchung);

foreach($buchung->getEinsatztage() as $e){
    $em->persist($e);
}
$em->flush();

Solution

  • Firstly, you have to understand that Doctrine and Symfony does not work with id's within your entities.In Einsatztag entity, your property should not be called $Buchung_id since it's an instance of buchung and not an id you will find out there.

    Moreover, in your loop, you add the Einsatztag to Buchung. But do you process the reverse set ?

    I do it this way to always reverse the set/add of entities.

    Einsatztag

    public function setBuchung(Buchung $pBuchung, $recurs = true){
         $this->buchung = $pBuchung;
    
         if($recurs){
            $buchung->addEinsatztag($this, false);
         }
    }
    

    Buchung

    public function addEinsatztag(Einsatztag $pEinsatztag, $recurs = true){
         $this->einsatztages[] = $pEinsatztag;
    
         if($recurs){
            $pEinsatztag->setBuchung($this, false);
         }
    }
    

    Then, when you will call

    $buchung->addEinsatztag($einsatztag);
    

    Or

    $einsatztag->set($buchung);
    

    The relation will be set on both side making your FK to be set. Take care of this, you'll have some behavior like double entries if you do not use them properly.

    SImplier , you can use default getter/setters and call them on both sides of your relation, using what you already have, like following:

    $einsatztag->set($buchung);
    $buchung->addEinsatztag($einsatztag);
    

    Hope it helped ;)