代码之家  ›  专栏  ›  技术社区  ›  Profet

条令级联={remove}通过onDelete=“级联”删除实体时不工作

  •  2
  • Profet  · 技术社区  · 8 年前

    我在使用原则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;
        }
    
    }
    

    每个 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;
        }
    
    }
    

    预期行为如下:

    • 这个 事件 实体在其父实体时自动删除 进口 已删除(与 onDelete="CASCADE" ).
    • 这个 事件 实体还包含对 媒体 实体,该实体在删除事件时必须删除。

    两者都很好:

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

    然而 如果我删除导入,尽管事件已删除,但与已删除事件相关的媒体不会 .

    对可能发生的事情有什么想法吗?谢谢

    1 回复  |  直到 8 年前
        1
  •  5
  •   Community Mohan Dere    6 年前

    您描述的问题是预期的行为。这个 onDelete="CASCADE" 选项强制数据库内部执行的行为,而选项 cascade={"remove"} 通过条令进行处理,并应用于在内存中执行的对象,如所述 in the documentation :

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

    这两种方法都是有效的,但正如所讨论的,它们意味着不同的事情 in this section .


    设置中实际发生的情况是,您希望 onDelete=“级联” 和 级联={“删除”} 在你的场景中一起行动,但由于他们的本性,他们不能这样做。

    事实上,因为在 Import 具有 级联={“删除”} ,当您删除 进口 :

    • 一 DELETE 在数据库中对对应的表执行操作 进口
    • 由于表中的外键用于 Event ,与您的 进口 已删除 直接在数据库中

    从此处,自用于 Media 没有任何外键引用 事件 表(因为它位于关联的反面)。


    有两件事你可以做到:

    反转媒体/事件关联并添加 onDelete=“级联” 在…上 媒体 桌子

    在里面 媒体php

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

    在里面 事件php

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

    使用此方法,删除 进口 数据库中的条目必然会删除相关的 事件 条目和通过相同的机制,相关 媒体 将被删除(所有这些都由您的数据库直接完成,条令刚刚发布一条 删除 上的操作 进口 表)。

    在中添加反向边 进口 和使用 级联={“删除”}

    如果添加一个逆 OneToMany 在里面 进口 具有 级联={“删除”} ,使用实体管理器执行的删除操作将级联到相关 事件 还将删除操作级联到任何关联 媒体 .

    如果您希望为这些实体执行生命周期事件,这可能很有用。


    这并不意味着您必须在两种方法之间进行选择。文件说明如下:

    然而,您应该知道,使用策略1(CASCADE=REMOVE)完全绕过任何外键onDelete=CASCADE选项,因为尽管如此,条令还是会显式地获取和删除所有关联实体。

    尽管如此 onDelete=CASCADE 除了 级联={“删除”} 如果您希望数据库保持正确的状态,这是有意义的。例如,如果执行 删除 直接查询(不使用实体管理器),在没有 onDelete=级联 您的RDBMS很可能会抱怨外键约束无效。