原则:一对多级联中的异常:违反完整性约束 1451

Doctrine: Exception in One-To-Many cascading: Integrity constraint violation 1451

我正在尝试使用 SymfonyDoctrine 构建一个非常基本的 CMS。我有像这样模拟我网站结构的实体:

实体:页面

/**
 * @ORM\Entity(repositoryClass="App\Repository\ContentTree\PageRepository")
 */
class Page extends SortableBase
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     * @ORM\OrderBy({"sort_order" = "ASC"})
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="Website", inversedBy="pages", cascade={"all"}, fetch="EAGER")
     */
    private $website;

    /**
     * Owning side of relation
     * @ORM\OneToMany(targetEntity="Section", mappedBy="page", fetch="EAGER")
     */
    private $sections;


    public function __construct()
    {
    ...

实体:部分

/**
 * @ORM\Entity(repositoryClass="App\Repository\ContentTree\SectionRepository")
 */
class Section extends SortableBase
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="Page", inversedBy="sections", cascade={"all"}, fetch="EAGER")
     */
    private $page;

    /**
     * Owning side of relation
     * @ORM\OneToMany(targetEntity="Entry", mappedBy="section", fetch="EAGER")
     */
    private $entries;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\SectionTemplating\SectionType", fetch="EAGER")
     */
    private $sectionType;


    public function __construct()
    {

实体:条目

/**
 * @ORM\Entity(repositoryClass="App\Repository\ContentTree\EntryRepository")
 */
class Entry extends SortableBase
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="Section", inversedBy="entries", cascade={"all"}, fetch="EAGER")
     */
    private $section;

    /**
     * Owning side of relation
     * @ORM\OneToMany(targetEntity="App\Entity\ContentTypes\Content", mappedBy="entry", fetch="EAGER")
     */
    private $contents;


    public function __construct()
    {
    ...

所以最后一个 Page 可以有 Sections 可以有 Entries 等等。现在,根据我从 docs 收集到的信息,我假设通过设置 cascades 我可以去使用 EntityManager 删除任何实体的实例(让说 Section) 它会自动删除该实例以及所有包含的实例 Entries.

然而,当我做类似的事情时:

$section = $this->getSectionByID($sectionid);

$entityManager = $this->getDoctrine()->getManager();
$entityManager->remove($section);
$entityManager->flush();

一旦 Section 有任何 Entries,我得到:

An exception occurred while executing 'DELETE FROM section WHERE id = ?' with params [10]:

SQLSTATE[23000]: Integrity constraint violation: 
1451 Cannot delete or update a parent row: 
a foreign key constraint fails (`webdata`.`entry`, CONSTRAINT `FK_2B219D70D823E37A` 
FOREIGN KEY (`section_id`) REFERENCES `section` (`id`))

我知道这是什么意思,但我就是想不出我应该在这里做些什么来强制 EntityManager 遍历我的实体图并从下到上删除所有内容。

级联本质上是一个瀑布,因为它决定了操作下一步将流向何处。

Cascade persist的意思是:当这个条目被持久化时,让操作也向下流到与这个条目相关的子实体。其他操作以类似的方式工作。

在您的情况下,级联似乎是从子实体启动的。当你打电话时:

$entityManager->remove($section);

实体管理器只注意到 page 的级联操作,而不是 entries

当您将级联操作放在 Section$entries 上时,由于类似的原因,您最终可能会以级联删除删除您的页面。

编辑:就注释而言,这将使:

在页面中:

/**
 * @ORM\ManyToOne(targetEntity="Website", inversedBy="pages", fetch="EAGER")
 */
private $website;

/**
 * Owning side of relation
 * @ORM\OneToMany(targetEntity="Section", mappedBy="page", fetch="EAGER" , cascade={"all"})
 */
private $sections;

在节中:

/**
 * @ORM\ManyToOne(targetEntity="Page", inversedBy="sections", fetch="EAGER")
 */
private $page;

/**
 * Owning side of relation
 * @ORM\OneToMany(targetEntity="Entry", mappedBy="section", fetch="EAGER", cascade={"all"})
 */
private $entries;

条目中:

/**
 * @ORM\ManyToOne(targetEntity="Section", inversedBy="entries", fetch="EAGER")
 */
private $section;

您确定要始终急切地获取所有内容吗?

事实证明,为了 Doctrineremove 级联到实体关系图中,只需像这样注释拥有方:

/**
 * Owning side of relation
 * @ORM\OneToMany(targetEntity="Page", mappedBy="website", cascade={"all"}, fetch="EAGER")
 */
private $pages;

然而,这实际上只是告诉 ORM 你想在一个例子中发生什么。 remove。这不足以模拟在实际调用数据库期间会发生什么。为此,必须在反面添加一个额外的 @ORM\JoinColumn(onDelete="CASCADE"),如下所示:

/**
 * @ORM\ManyToOne(targetEntity="Website", inversedBy="pages", fetch="EAGER")
 * @ORM\JoinColumn(onDelete="CASCADE")
 */
private $website;

有了这个,一切都按预期进行。我也终于能够通过 phpMyAdmin 手动删除条目,这之前也给了我错误。