【问题标题】:Doctrine2: Many-to-One delete relations on updateDoctrine2:更新时多对一删除关系
【发布时间】:2026-02-08 14:35:01
【问题描述】:

我有一个可以拥有很多截图的软件。

这是软件类:

class Software
{
   public function __construct()
   {
       $this->screenshots = new ArrayCollection();
   }

   /**
    * @ORM\OneToMany(targetEntity="Screenshot", mappedBy="software", cascade={"persist"})
    * @ORM\OrderBy({"sequence" = "ASC", "id" = "ASC"})
    */
   private $screenshots;


   public function setScreenshots($screenshots)
   {
       $this->screenshots = $screenshots;
   }
}

这是截图类:

class Screenshot
{
   /**
    * @ORM\ManyToOne(targetEntity="Software", inversedBy="screenshots")
    * @ORM\JoinColumn(name="software_id", referencedColumnName="id")
    */
   private $software;

   /**
    * @param mixed $software
    */
   public function setSoftware($software)
   {
       $this->software = $software;
   }

当我生成一些新的屏幕截图时,将它们放入数组集合并调用 $software->setScreenshots($newScreenshots) 使用新的屏幕截图一切正常。新的屏幕截图已保存,并且它们具有对软件的引用。

但是当我生成一些其他截图并再次调用该方法时,它并没有删除旧截图。刚刚添加了新的屏幕截图。

有没有办法提供某种级联选项,以便删除旧的屏幕截图?或者至少删除对软件的引用?

【问题讨论】:

    标签: symfony doctrine-orm one-to-many cascade many-to-one


    【解决方案1】:

    您可以让数据库完成这项工作(DBAL 方面):

    user:
            targetEntity: User
            inversedBy: points
            joinColumn:
                name: user_id
                referencedColumnName: id
                onDelete: 'cascade' #this is important for u
            fetch: EAGER
    

    【讨论】:

    • 我刚试过这个,遗憾的是它没有解决问题。我猜这是因为我没有删除该软件。我只是在更新它。
    • 所以试试 onUpdate 选项 - 我不知道它会起作用还是不存在 :) 用 lib 进行实验!
    【解决方案2】:

    最简单的解决方案是手动删除它们:

    foreach ( $software->getScreenshots() as $scrshot){
        $em->remove($scrshot);
    }
    $software->setScreenshots($newScreenshots);
    

    但是,除了这个解决方案之外,您是否尝试过在反面或关系上定义 orphanRemoval?也许这会有所帮助,但我不确定:

    /**
     * @ORM\OneToMany(targetEntity="Screenshot", mappedBy="software", cascade={"persist"}, orphanRemoval=true)
     * @ORM\OrderBy({"sequence" = "ASC", "id" = "ASC"})
     */
    private $screenshots;
    

    【讨论】:

    • 我考虑过手动删除,但我对在我的实体中使用这种逻辑感到不舒服。 orphanRemoval 只允许在软件端使用,它不能按我的需要工作。
    • 是的,我也会避免将实体与删除逻辑合并,因此我会将其放入控制器/服务中。
    • 我正在使用非规范化 json 的对象构建器。很遗憾,我无法将逻辑放在实体之外的某个地方。