解決策は、EntityB
(最初)からEntityA
への参照を削除することです。この場合、DoctrineはEntityB
をそのまま使用しようとします。我々はorphanRemoval=true
と組み合わせる場合でも、私たちは目指した結果を得るでしょう:
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;
}
...
}
トピックオフ
:私は質問で述べたので利点があろうと、コレクション
の交換EntityA#replaceEntityBs(ArrayCollection $entityBs)
のようなメソッドを実装することができます、私はここで可能な実装を共有したいと思います。
最初のナイーブな試みは、すべてEntityBs
を削除してから、新しい要素を追加(永続化)することでした。
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;
}
しかし含まsetEntityBs(...)
既存EntityBs
の入力コレクションの場合(つまり、更新されSHOLD)、それはそれらの削除と唯一の新しい要素が持続してしまったにつながりました。ここで
が望んだとして機能するソリューションです:
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);
}
}
}