通过onDelete =“ CASCADE”删除实体时,Doctrine Cascade = {remove}不起作用

Pro*_*fet 2 php doctrine-orm

我在使用Doctrine 2的实体之间级联关系时遇到问题。

我有一个Media与父级事件相关的实体:

class Media
{

    /**
     * @ORM\OneToOne(targetEntity="Event", mappedBy="media")
     */
    private $event;

    public function getEvent()
    {
        return $this->event;
    }

    public function setEvent(Event $event)
    {
        $this->event = $event;
    }

}
Run Code Online (Sandbox Code Playgroud)

每个Event都与媒体(双向)有关,也与Import实体有关。

class Event
{

    /**
     * @ORM\JoinColumn(name="media", referencedColumnName="id", onDelete="SET NULL")
     * @ORM\OneToOne(targetEntity="Media", inversedBy="event", cascade={"persist", "remove"}, orphanRemoval=true)
     */
    private $media;

    public function getMedia()
    {
        return $this->media;
    }

    public function setMedia(Media $media = null)
    {
        $this->media = $media;
    }


    /**
     * @ORM\JoinColumn(name="import", referencedColumnName="id", nullable=true, onDelete="CASCADE")
     * @ORM\ManyToOne(targetEntity="Import")
     */
    private $import;

    public function getImport()
    {
        return $this->import;
    }

    public function setImport(Import $import = null)
    {
        $this->import = $import;
    }

}
Run Code Online (Sandbox Code Playgroud)

预期的行为如下:

  • Event实体的父级Import被删除(带有的ManyToOne关系onDelete="CASCADE")时,该实体会自动删除。
  • Event实体还包含对实体的引用(OneToOne关系)Media,在删除事件时必须将其删除。

两者都运行良好:

  • 如果删除导入,则会删除所有相关事件。
  • 如果删除事件,则会删除相关的媒体。

但是,如果我删除导入,则尽管事件被删除,但与删除的事件相关的媒体不是

关于可能发生的事情有什么想法吗?谢谢!

Ala*_* T. 5

您正在描述的问题是预期的行为。该onDelete="CASCADE"选项强制执行一种行为,该行为由数据库内部执行,而该选项cascade={"remove"}通过Doctrine处理并应用于文档中所述的在内存中执行的对象:

级联操作在内存中执行。这意味着将要执行级联操作时,将集合和相关实体提取到内存中(即使它们被标记为惰性)。这种方法允许对每个操作执行实体生命周期事件。

两种方法都是有效的,但它们暗示了本节中讨论的不同内容。


设置实际发生的情况是,您希望混合使用,onDelete="CASCADE"并且cascade={"remove"}在您的方案中一起使用,但由于它们的本性,它们是无法实现的。

因为它是,因为你不具备反侧Importcascade={"remove"},当你删除Import

  • 一个DELETE运行在你的数据库对应表进行Import
  • 由于使用的表中的外键Event,与您有关的事件直接在数据库Import中删除

从那里开始,由于用于的表Media没有任何引用该Event表的外键(因为它在关联的相反侧),因此不执行其他任何操作。


您可以执行以下两项操作来完成这项工作:

反转媒体/事件关联并添加onDelete="CASCADE"Media表中

Media.php

/**
 * @ORM\OneToOne(targetEntity="Event", inversedBy="media")
 * @ORM\JoinColumn(onDelete="CASCADE")
 */
private $event;
Run Code Online (Sandbox Code Playgroud)

Event.php

/**
 * @ORM\OneToOne(targetEntity="Media", mappedBy="event")
 */
private $media;
Run Code Online (Sandbox Code Playgroud)

使用这种方法,删除Import数据库中的一项将必然删除相关的Event项,并且通过相同的机制,相关的项Media也将被删除(所有这些都直接由您的数据库完成,Doctrine只是DELETEImport表上执行了一项操作)。

在其中添加反面Import并使用cascade={"remove"}

如果OneToManyImportwith中添加反函数,则使用cascade={"remove"}实体管理器执行的删除操作将级联到相关的Event实体,这些实体还将把删除操作级联到任何关联的实体Media

如果您希望对那些实体执行生命周期事件,这将很有用。


这并不意味着您必须在两种方法之间进行选择。该文档指出以下内容:

但是,您应该知道,使用策略1(CASCADE = REMOVE)会完全绕过onDelete = CASCADE选项的任何外键,因为尽管如此,Doctrine仍将显式获取并删除所有关联的实体。

话虽如此,如果您希望数据库保持适当的状态onDelete=CASCADE,则除了cascade={"remove"}具有合理的意义外。例如,如果DELETE直接执行查询(不使用实体管理器),则必须删除相关条目,onDelete=CASCADE并且RDBMS很可能会抱怨无效的外键约束。