(doctrine2 + symfony2) 级联删除:完整性约束违规 1451

15

首先,抱歉我的英语不太好...

我有四个实体:用户(User)、应用程序(Application)、捆绑包(Bundle)和实体(Entity)。以下是它们的关系(具有级联持久性和删除,请参见下面的代码):

  • 用户(User)1-n 应用程序(Application)
  • 应用程序(Application)1-n 捆绑包(Bundle)
  • 捆绑包(Bundle)1-n 实体(Entity)

这很有效。但一个用户可以将他的两个实体设置为默认值,我需要直接访问它们。

因此,我在用户上添加了两个字段,entity1和entity2,并建立了1-1关系。现在我的应用程序崩溃了:

An exception occurred while executing 'DELETE FROM bundle WHERE id = ?' with params {"1":13}:

SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`misc`.`entity`, CONSTRAINT `FK_E284468F1FAD9D3` FOREIGN KEY (`bundle_id`) REFERENCES `bundle` (`id`))

我尝试了几件事情,包括那些在这篇文章中提到的,但是我无法修复它。

欢迎任何帮助,提前致谢。

编辑:我需要指出,用户-实体关系是可选的:User的entity1和entity2都可以为null。即使它们都是null,错误仍会发生。

这里是我的实体定义:

# User :
    /**
     * @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Application", mappedBy="user", cascade={"remove"}, orphanRemoval=true)
     * @ORM\OrderBy({"name" = "ASC"})
     */
    protected $applications;

    /**
     * @ORM\OneToOne(targetEntity="\sfCommands\ContentBundle\Entity\Entity")
     * @ORM\JoinColumn(name="entity1_id", referencedColumnName="id")
     */
    private $entity1;

    /**
     * @ORM\OneToOne(targetEntity="\sfCommands\ContentBundle\Entity\Entity")
     * @ORM\JoinColumn(name="entity2_id", referencedColumnName="id")
     */
    private $entity2;

#Application :
    /**
     * @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Bundle", mappedBy="application", cascade={"remove"}, orphanRemoval=true)
     * @ORM\OrderBy({"name" = "ASC"})
     */
    protected $bundles;

    /**
     * @ORM\ManyToOne(targetEntity="\sfCommands\UserBundle\Entity\User", inversedBy="applications", cascade={"persist"})
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
     */
    protected $user;

#Bundle :
    /**
     * @ORM\ManyToOne(targetEntity="\sfCommands\ContentBundle\Entity\Application", inversedBy="bundles", cascade={"persist"})
     * @ORM\JoinColumn(name="application_id", referencedColumnName="id")
     */
    protected $application;

    /**
     * @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Entity", mappedBy="bundle", cascade={"remove"}, orphanRemoval=true)
     * @ORM\OrderBy({"name" = "ASC"})
     */
    protected $entitys;

#Entity :
    /**
     * @ORM\ManyToOne(targetEntity="\sfCommands\ContentBundle\Entity\Bundle", inversedBy="entitys", cascade={"persist"})
     * @ORM\JoinColumn(name="bundle_id", referencedColumnName="id")
     */
    protected $bundle;

你尝试删除的 bundle_id 是否与任何用户字段中的实体(entity1_id 或 entity2_id)相关联? - Pankrates
即使Bundle的子项(Entity)不在用户字段(entity1_id或entity2_id)中,删除操作仍然会执行。听起来像是级联操作根本没有起作用。 - bgaze
4个回答

40

所以,多亏了这个法语论坛,我解决了问题。

我需要在 @ORM\JoinColumn 中添加nullable=trueonDelete="SET NULL"

这是可行的配置,也许会帮助到别人:

#User.
    /**
     * @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Application", mappedBy="user", cascade={"remove"}, orphanRemoval=true)
     * @ORM\OrderBy({"name" = "ASC"})
     */
    protected $applications;

    /**
     * @ORM\OneToOne(targetEntity="\sfCommands\ContentBundle\Entity\Entity")
     * @ORM\JoinColumn(name="entity1_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
     */
    private $entity1;

    /**
     * @ORM\OneToOne(targetEntity="\sfCommands\ContentBundle\Entity\Entity")
     * @ORM\JoinColumn(name="entity2_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
     */
    private $entity2;

#Application.
    /**
     * @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Bundle", mappedBy="application", cascade={"remove"}, orphanRemoval=true)
     * @ORM\OrderBy({"name" = "ASC"})
     */
    protected $bundles;

    /**
     * @ORM\ManyToOne(targetEntity="\sfCommands\UserBundle\Entity\User", inversedBy="applications", cascade={"persist"})
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
     */
    protected $user;

#Bundle.
    /**
     * @ORM\ManyToOne(targetEntity="\sfCommands\ContentBundle\Entity\Application", inversedBy="bundles", cascade={"persist"})
     * @ORM\JoinColumn(name="application_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
     */
    protected $application;

    /**
     * @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Entity", mappedBy="bundle", cascade={"remove"}, orphanRemoval=true)
     * @ORM\OrderBy({"name" = "ASC"})
     */
    protected $entitys;

#Entity.
    /**
     * @ORM\ManyToOne(targetEntity="\sfCommands\ContentBundle\Entity\Bundle", inversedBy="entitys", cascade={"persist"})
     * @ORM\JoinColumn(name="bundle_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
     */
    protected $bundle;

23

如果您使用注释,请使用 onDelete="CASCADE"

/**
 * @ORM\ManyToOne(targetEntity="Report", inversedBy="responses")
 * @ORM\JoinColumn(name="reportId", referencedColumnName="id",onDelete="CASCADE")
 */

如果你正在使用yml,则使用onDelete: CASCADE。

joinColumn:
      name: pid
      referencedColumnName: id
      onDelete: CASCADE

这对我很有用。我遇到了这种问题并得到了解决。谢谢。 - Samia Ruponti
太棒了! - kabrice
这不是正确的答案。 onDeleteorphanRemovalcascade ="remove" 是实现你所需的三种方法。在此处查看它们之间的区别(https://dev59.com/cF4c5IYBdhLWcg3w1tSO)。 - Jorj

3

onDelete="CASCADE"同样可以正常使用。但不要忘记在数据库层面的变更生效之前运行app/console doctrine:schema:update --force命令。


1
在我的情况下,nullable=true & onDelete="SET NULL" 的组合只允许删除用户,而不是他们的预订,这导致了预订表中的孤立记录。即使在User实体上设置cascade={"remove"} + orphanRemoval=true的OneToMany关系也没有帮助。因此,我的建议是使用onDelete="CASCADE",这将触发删除用户记录以及相关的预订,而不会出现任何问题。 - basejumper
但是,如果您只删除引用而不是用户,则不会触发onDelete。在我的情况下,我最终在弱实体的FK中得到一个空值。这应该是非空的。 - juanmf

1
有时候,孤儿删除(orphanRemoval)无法正常工作,因为它依赖于(被计划在)PersistencCollection中。而我们可能会调用ArrayCollection#removeElement()
以下是PersistencCollection#remove()的片段。
    if ($this->association !== null &&
        $this->association['type'] & ClassMetadata::TO_MANY &&
        $this->owner &&
        $this->association['orphanRemoval']) {
        $this->em->getUnitOfWork()->scheduleOrphanRemoval($removed);
    }

而 ArrayCollection 并不会这样做。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接