Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doctrine "A new entity was found through the relationship" error

First off I want to say I've read through all the docs and googled this plenty before posting this question. I know what that error means (un-persisted entity in a relationship)

I'm getting this error where I think I shouldn't be getting it.

I have a OneToMany Bi-Directional relationship as follow:

Class Channel
{
    /** 
    * @ORM\OneToMany(targetEntity="Step", mappedBy="channel", cascade={"all"}, orphanRemoval=true)
    * @ORM\OrderBy({"sequence" = "ASC"})
    */
    protected $steps;
}

Class Step
{
    /** 
    * @ORM\ManyToOne(targetEntity="Channel", inversedBy="steps")
    */
    protected $channel;
}

One Channel can have many Steps and the owning side is Channel. After I upgraded from Doctrine 2.4 to 2.5 I'm getting this error:

Doctrine\ORM\ORMInvalidArgumentException: A new entity was found through the relationship 'Company\MyBundle\Entity\Step#channel' that was not configured to cascade persist operations for entity

why is it even finding new relationships from the inverse side? Here's my code:

$channel = new Channel();
$step = new Step();
$channel->addStep($step);
$em->persist($channel);
$em->flush();

Thanks!

like image 344
Reza S Avatar asked May 27 '15 01:05

Reza S


2 Answers

You're right: Doctrine looks only for changes into owning side but you're wrong: owning side of your relationship is Step, not Channel.

Why is step the owning side? Because is the entity that has foreign key. Even Doctrine documentation says to you

The owning side has to use the inversedBy attribute of the OneToOne, ManyToOne, or ManyToMany mapping declaration. The inversedBy attribute contains the name of the association-field on the inverse-side.

Possible solutions:

  • Try to invert cascade operations by putting cascade={"all"} into Step entity (are you sure that all is the correct choice?)

  • Persist explicitly both entities:

    $channel = new Channel();
    $step = new Step();
    $channel->addStep($step);
    $em->persist($channel);
    $em->persist($step);
    $em->flush();
    

    here you can read why second way provided here is fine too

like image 64
DonCallisto Avatar answered Oct 16 '22 08:10

DonCallisto


You try to persist $channel, but it has Step entity inside. So in Doctrine now you have 2 entities that are queued for inserting. Then Doctrine order entities in the order where first is Step because it has channel_id foreign key (that is empty now). Doctrine try persist this entity and when it understands that channel_id is empty it sees for cascade rules for persisting. It doesn't see any cascade rules and throw you this exception.

like image 39
Michael Sivolobov Avatar answered Oct 16 '22 09:10

Michael Sivolobov