【问题标题】:Why do I need to flush() after remove() and before persist() in doctrine为什么在学说中我需要在 remove() 之后和 persist() 之前进行 flush()
【发布时间】:2017-03-23 15:43:05
【问题描述】:

我有以下代码:

//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();

【问题讨论】:

  • $files 属性上的 orphanRemoval=true 怎么样?然后你有一个文件Collection,如果需要,你可以在Record实体刷新上重置
  • 孤儿不起作用,问题在于文件上的 'cascade={"persist"}'。我会再做一些调试,看看能不能解决这个问题

标签: php symfony doctrine-orm


【解决方案1】:

cascade 参数有一个选项:'remove'、'persist'、'refresh'、'merge' 和 'detach'。

把它们当作标志,这样你就可以写了:

cascade={"persist","remove"}

甚至:

cascade={"all"}

也许这会有所帮助...

【讨论】:

    【解决方案2】:

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

    第一种场景:在Entity中不设置任何级联逻辑,所有操作都手动处理。

    记录实体

    /**
     * @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 代码更少,可读性更好。

    我会为任何 cmets/tips 保留这个答案,并在本周关闭它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-18
      • 2011-04-01
      • 1970-01-01
      • 2014-02-17
      • 2016-09-10
      • 1970-01-01
      相关资源
      最近更新 更多