Symfony OneToMany updates instead of insert

232 views Asked by At

I am a beginner in Symfony.

I have a strange problem in my form.

I have 2 entities : Proposal_Lsi and Lsi_Beams. One proposal can have multiple beams, but a beam can only have one proposal. I figured I should use a OneToMany/ManyToOne relation, and that my owning side is the beam one, and inverse side is proposal.

I followed the official guide at https://symfony.com/doc/3.1/form/form_collections.html about Form Collections.

Everything renders just fine, I can submit a new proposal with multiple beams, and all is correctly stored in the database.

The problem occurs whenever I try to add new beams to my proposal : the systems overwrites (update query) existing beams (starting by the first one in the database) instead of adding new ones (insert query).

What am I missing ?

Here's some of my code, if that can help.

Proposal Class:

class Proposal_lsi{
/**
* @ORM\OneToOne(targetEntity="Emir2Bundle\Entity\Proposal", inversedBy="proposal_lsi")
* @ORM\JoinColumn(name="proposal", referencedColumnName="id")
* @ORM\Id
*/  
private $proposal;

/**
* @ORM\OneToMany(targetEntity="Emir2Bundle\Entity\Lsi_beams", mappedBy="proposal_lsi")
*/  
private $lsi_beams;

...

/**
 * Add lsiBeam
 *
 * @param \Emir2Bundle\Entity\Lsi_beams $lsiBeam
 * @return Proposal_lsi
 */
public function addLsiBeam(\Emir2Bundle\Entity\Lsi_beams $lsiBeam)
{
    $lsiBeam->setProposalLsi($this);
    $this->lsi_beams[] = $lsiBeam;

    return $this;
}

}

Beams Class:

class Lsi_beams{
/**
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
* @ORM\ManyToOne(targetEntity="Emir2Bundle\Entity\Proposal_lsi", inversedBy="lsi_beams", cascade={"persist"})
* @ORM\JoinColumn(name="proposal_lsi", referencedColumnName="proposal", nullable=false)
*/
private $proposal_lsi;

...
}

And the form in the controller :

$form = $this->createFormBuilder($proposallsi)
        ->setAction($this->generateUrl('lsi_submission', array('id' => $id)))
        ->setMethod('POST')
        ->add('lsi_beams', CollectionType::class, array(
            'entry_type'    => LsiBeamsType::class,
            'allow_add'     => true,
            'allow_delete'      => true,
            'prototype'     => true,
            'by_reference'  => false
            )
        )
...

What am I doing wrong ? Let me know if you need more code.

Thanks for any reply !

1

There are 1 answers

1
WordPress Speed On

Notes:

  1. use Doctrine ArrayCollection to better keep track of collections
  2. put cascade={"persist"} at the inverse side of association (where you have mappedBy)
  3. Keep entity names singular (e.g. Lsi_beam instead of Lsi_beams)
  4. Keep your naming strategy clear and strait. Don't use undescores in your class & property names (e.g. use $lsiBeams instead of $lsi_beams)

ProposalLsi

use Doctrine\Common\Collections\ArrayCollection;

class ProposalLsi
{
    /**
    * @ORM\OneToMany(targetEntity="LsiBeam", mappedBy="proposalLsi", cascade={"persist"})
    */  
    private $lsiBeams;

    public function __construct()
    {
        $this->lsiBeams = new ArrayCollection();
    }

    public function addLsiBeam(LsiBeams $lsiBeam)
    {
        if ($this->lsiBeams->contains($lsiBeam)) {

            return;
        } else {

            $lsiBeam->setProposalLsi($this);
            $this->lsiBeams->add($lsiBeam);
        }
    
        return $this;
    }

    public function removeLsiBeam(LsiBeams $lsiBeam)
    {
        if (!$this->lsiBeams->contains($lsiBeam)) {

            return;
        } else {

            $lsiBeam->setProposalLsi(null);
            $this->lsiBeams->removeElement($lsiBeam);
        }
    
        return $this;
    }
}

LsiBeam

class LsiBeam
{
    /**
    * @ORM\ManyToOne(targetEntity="ProposalLsi", inversedBy="lsiBeams")
    */
    private $proposalLsi;

    public function setProposalLsi(?ProposalLsi $proposalLsi)
    {
        $this->proposalLsi = $proposalLsi;
    }

}