为什么我需要在remove()之后和在doctrine中的persist()之前刷新()

时间:2017-03-23 15:43:05

标签: php symfony doctrine-orm

我有以下代码:

//Delete old existing file(s)
$files = $record->getFiles();

foreach ($files as $file) {
   $em->remove($file);
}

$em->flush();

$link = $record->getLink() ? $record->getLink() : new Link();
$link->setRecord($record);
$link->setUrl($metaData['location']);

$em->persist($link);

$em->flush();

我需要拨打第一个flush(),否则$file实体不会被删除..为什么不使用第二个flush()删除它们?

供参考,以下是Record

的关系定义
/**
 * @var \AppBundle\Entity\Link
 *
 * @ORM\OneToOne(targetEntity="AppBundle\Entity\Link", cascade={"persist"}, mappedBy="record")
 */
private $link;

/**
 * @var \AppBundle\Entity\File
 *
 * @ORM\OneToMany(targetEntity="AppBundle\Entity\File", cascade={"persist"}, mappedBy="record")
 */
private $files;

此外,使用单个flush()的代码工作正常(它正在删除OneOnOne实体而不是OneToMany):

 //Delete old existing link
 $link = $record->getLink();
 if ($link) {
      $em->remove($link);
 }

 $file = $record->getFile() ? $record->getFile() : new File();
 $file->setRecord($record);

 $em->persist($file);

 $em->flush();

2 个答案:

答案 0 :(得分:1)

我找到了两种使代码工作的方法,它采用两种不同的方法:

第一种情况:不要在实体中设置任何级联逻辑并手动处理所有操作。

记录实体

/**
 * @var \AppBundle\Entity\Link
 *
 * @ORM\OneToOne(targetEntity="AppBundle\Entity\Link", mappedBy="record")
 */
private $link;

/**
 * @var \AppBundle\Entity\File
 *
 * ORM\OneToMany(targetEntity="AppBundle\Entity\File", mappedBy="record")
 */
private $files;

<强>控制器

//Delete old existing file(s)
$files = $record->getFiles();

foreach ($files as $file) {
    $fileService->deleteFile($file);
    //Remove the *owning* entity of the relationship
    $em->remove($file);
}

$em->flush();
$em->clear();

//We need to call clear() to remove all existing references of files 
//from the $record entity. Get the record again after this.
$record = $this->getRecordRepository()->findActive($id);

$link = $record->getLink() ? $record->getLink() : new Link();
$link->setRecord($record);
$link->setUrl($metaData['location']);

$em->persist($link);
$record->setType(Record::TYPE_LINK);

$em->flush();

第二种情况:从$record角度处理所有数据库操作,让cascadeorphanRemoval完成剩下的工作

记录实体

/**
 * @var \AppBundle\Entity\Link
 *
 * @ORM\OneToOne(targetEntity="AppBundle\Entity\Link", cascade={"persist", "remove"}, mappedBy="record", orphanRemoval=true)
 */
private $link;

/**
 * @var \AppBundle\Entity\File
 *
 * @ORM\OneToMany(targetEntity="AppBundle\Entity\File", cascade={"persist", "remove"}, mappedBy="record", orphanRemoval=true)
 */
private $files;

<强>控制器

//Delete old existing file(s)
$files = $record->getFiles();

foreach ($files as $file) {
    $fileService->deleteFile($file);
    $record->removeFile($file);
}

$link = $record->getLink() ? $record->getLink() : new Link();
$link->setRecord($record);
$link->setUrl($metaData['location']);

$em->persist($link);
$record->setType(Record::TYPE_LINK);

$em->flush();

我个人赞成第二种方法,它需要更少的PHP代码更具可读性。

我会在任何评论/提示中留下这个答案,并在本周结束。

答案 1 :(得分:0)

cascade参数有一个选项:&#39;删除&#39;,&#39;坚持&#39;,&#39;刷新&#39;&#39;合并&#39;,和&#39;分离&#39;。

将它们视为标志,以便您可以写:

cascade={"persist","remove"}

甚至:

cascade={"all"}

也许这有帮助...