douhui3330 2016-09-06 22:59
浏览 112
已采纳

禁用Doctrine外键约束

I have a relationship on one of my models:

/**
* @ORM\ManyToOne(targetEntity="Page", cascade="persist")
* @ORM\JoinColumn(name="page_id", referencedColumnName="id")
*/
private $parentPage;

And when I delete the parent page, I get this error:

Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails

Basically my models are a page, and page revision. When I delete the page I don't want to delete the revisions. I also want to keep the page_id on the page revisions (i.e. not set it to null).

How can I do this with Doctrine?

  • 写回答

4条回答 默认 最新

  • drvfqr5609 2016-09-13 07:55
    关注

    By definition you cannot delete the record that the foreign key is pointing at without setting the key to null (onDelete="SET NULL") or cascading the delete operation (There are two options - ORM Level: cascade={"remove"} | database level: onDelete="CASCADE").
    There is the alternative of setting a default value of a still existing record, but you have to do that manually, I don't think Doctrine supports this out-of-the-box(please correct me if I am wrong, but in this case setting a default value is not desired anyway).

    This strictness is reflecting the concept of having foreign key constraints; like @Théo said:

    a FK is to ensure data consistency.

    Soft delete (already mentioned) is one solution, but what you could also do is add an additional removed_page_id column that you sync with the page_id just before you delete it in a preRemove event handler (life cycle callback). Whether such information has any value I wonder but I guess you have some use for it, otherwise you wouldn't ask this question.

    I am definitely not claiming this is good practice, but it is at least something that you can use for your edge case. So something in the line of:

    In your Revision:

    /**
     * @ORM\ManyToOne(targetEntity="Page", cascade="persist")
     * @ORM\JoinColumn(name="page_id", referencedColumnName="id", onDelete="SET NULL")
     */
    private $parentPage;
    
    /**
     * @var int
     * @ORM\Column(type="integer", name="removed_page_id", nullable=true)
     */
    protected $removedPageId;
    

    And then in your Page:

    /** 
     * @ORM\PreRemove 
     */
    public function preRemovePageHandler(LifecycleEventArgs $args)
    {
        $entityManager = $args->getEntityManager();
        $page = $args->getEntity();
        $revisions = $page->getRevisions();
        foreach($revisions as $revision){
            $revision->setRemovedPageId($page->getId());
            $entityManager->persist($revision);
        }
        $entityManager->flush();
    }
    

    Alternatively you could of course already set the correct $removedPageId value during construction of your Revision, then you don't even need to execute a life cycle callback on remove.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥50 导入文件到网吧的电脑并且在重启之后不会被恢复
  • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝
  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
  • ¥15 错误 LNK2001 无法解析的外部符号
  • ¥50 安装pyaudiokits失败
  • ¥15 计组这些题应该咋做呀
  • ¥60 更换迈创SOL6M4AE卡的时候,驱动要重新装才能使用,怎么解决?
  • ¥15 让node服务器有自动加载文件的功能