This post is going to show us where and when to or not to use cascade={"persist"} operations.


Info


Setting cascade={"persist"} property on both sides ("inverse" and "owning") is unnecessary but it wouldn't cause any problems. It is often used on "inverse" side where mappedBy property of the relationship is set. You may call it "parent/independent" side as well. Assume that we have a League 1-n Team (OneToMany) relationship so the "inverse side" is League in this case.


Structure


class League
{
/**
* @ORM\OneToMany(targetEntity="Team", mappedBy="league")
*/
private $teams;

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

class Team
{
/**
* @ORM\ManyToOne(targetEntity="League", inversedBy="teams")
* @ORM\JoinColumn(name="league_id", referencedColumnName="id", nullable=false)
*/
private $league;
}

Examples


Cascade 1) No cascade at all


In such case you must manually persist both entities.


League: @ORM\OneToMany(targetEntity="Team", mappedBy="league")
Team: @ORM\ManyToOne(targetEntity="League", inversedBy="teams")

$league = new League();
$team = new Team();

// add or set Team in League
// add or set League in Team

$entityManager->persist($league);
$entityManager->persist($team);
$entityManager->flush();

Cascade 2) Cascade on League


In such case you must manually persist League. Persisting Team is unnecessary but wouldn't cause any harm.


League: @ORM\OneToMany(targetEntity="Team", mappedBy="league", cascade={"persist"})
Team: @ORM\ManyToOne(targetEntity="League", inversedBy="teams")

$league = new League();
$team = new Team();

// add or set Team in League
// add or set League in Team

$entityManager->persist($league);
$entityManager->persist($team); // Unnecessary
$entityManager->flush();

Cascade 3) Cascade on Team


In such case you must manually persist Team. Persisting League is unnecessary but wouldn't cause any harm.


League: @ORM\OneToMany(targetEntity="Team", mappedBy="league")
Team: @ORM\ManyToOne(targetEntity="League", inversedBy="teams", cascade={"persist"})

$league = new League();
$team = new Team();

// add or set Team in League
// add or set League in Team

$entityManager->persist($league); // Unnecessary
$entityManager->persist($team);
$entityManager->flush();

Cascade 4) Cascade on League and Team


In such case you can manually either persist League or Team. Persisting both is unnecessary but wouldn't cause any harm.


League: @ORM\OneToMany(targetEntity="Team", mappedBy="league", cascade={"persist"})
Team: @ORM\ManyToOne(targetEntity="League", inversedBy="teams", cascade={"persist"})

$league = new League();
$team = new Team();

// add or set Team in League
// add or set League in Team

$entityManager->persist($league); // Either this
$entityManager->persist($team); // or this
$entityManager->flush();

Result


It is enough to persist the entity where cascade={"persist"} property is set and ignore persisting the other one. Setting cascade={"persist"} on both entities might be useful when you want to persist either entities.


Common error


When something goes wrong with your persist operation (happens when you forget to use cascade={"persist"}), you'll get an error like this: A new entity was found through the relationship 'League#teams' that was not configured to cascade persist operations for entity: Team@000000006fefb0fd00007fa33b3653bf. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ORM\...(..,cascade={"persist"}).. The unknown entity in this case is Team so it is telling you to either run $entityManager->persist($team); or just add cascade={"persist"} property on to entity you are currently persisting which is League, not the Team.


# As you can see below, our mapping is missing cascade property

League: @ORM\OneToMany(targetEntity="Team", mappedBy="league")
Team: @ORM\ManyToOne(targetEntity="League", inversedBy="teams")

$league = new League();
$team = new Team();

// add or set Team in League
// add or set League in Team

$entityManager->persist($league);
// $entityManager->persist($team); // -> You forgot to use this so either enable it or just add cascade={"persist"} to League entity
$entityManager->flush();