The solution is to remove the reference to EntityA
from the EntityB
(first). In this case Doctrine will try to persist an EntityB
without. But if we combine this with orphanRemoval=true
, we'll get the aimed result:
class EntityA
{
...
/**
* @var ArrayCollection
* @ORM\OneToMany(targetEntity="EntityB", mappedBy="entityA", cascade={"persist"}, orphanRemoval=true)
*/
protected $entityBs;
...
public function removeEntityB(EntityB $entityB)
{
$this->entityBs->removeElement($entityB);
$entityB->setEntityA(null);
return $this;
}
...
}
class EntityB
{
...
/**
* @var EntityA
*
* @ORM\ManyToOne(targetEntity="EntityA", inversedBy="entityBs")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="entity_a_id", referencedColumnName="id")
* })
*/
protected $entityA;
...
/**
* @param EntityA $entityA
* @return EntityB
*/
public function setEntityA(EntityA $entityA = null)
{
$this->entityA = $entityA;
return $this;
}
...
}
Off topic: Replacing a collection
Since I noted in the question, that an advantage would be, that one can implement a method like EntityA#replaceEntityBs(ArrayCollection $entityBs)
, I want to share here a possible implementation.
The first naïve attempt was just to remove all EntityBs
and then add (and persist) the new elements.
public function setEntityBs($entityBs)
{
$this->removeEntityBs();
$this->entityBs = new ArrayCollection([]);
/** @var EntityB $entityB */
foreach ($entityBs as $entityB) {
$this->addEntityB($entityB);
}
return $this;
}
public function removeEntityBs()
{
foreach ($this->getEntityBs() as $entityB) {
$this->removeEntityB($entityB);
}
return $this;
}
But if the input collection of the setEntityBs(...)
contained existing EntityBs
(that shold be updated), it led to deleting of them and only the new elements got persisted.
Here is a solution, that works as wished:
public function setEntityBs($entityBs)
{
$this->removeEntityBsNotInList($entityBs);
$this->entityBs = new ArrayCollection([]);
/** @var EntityB $entityB */
foreach ($entityBs as $entityB) {
$this->addEntityB($entityB);
}
return $this;
}
private function removeEntityBsNotInList($entityBs)
{
foreach ($this->getEntityBs() as $entityB) {
if ($entityBs->indexOf($entityB) === false) {
$this->removeEntityB($entityB);
}
}
}