Doctrine: Исключение при каскадировании один ко многим: нарушение ограничения целостности 1451 - PullRequest
1 голос
/ 08 марта 2020

Я пытаюсь построить очень базовую c CMS, используя Symfony и Doctrine. У меня есть объекты, имитирующие структуру моих сайтов, например:

Entity: Page

/**
 * @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()
    {
    ...

Entity: Section

/**
 * @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()
    {

Сущность: Entry

/**
 * @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 и так далее. Теперь, исходя из того, что я собрал из документов , я исходил из того, что при настройке cascades я могу просто go и использовать 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 пройти через мою сущность график и удалить все снизу вверх.

Ответы [ 2 ]

1 голос
/ 08 марта 2020

Каскад - это, по сути, водопад, в том смысле, что он определяет, куда следующие операции будут перетекать.

Cascade persist означает: когда эта запись будет сохранена, пусть эта операция также переходит к дочернему элементу лица, связанные с этим. Другие операции работают аналогичным образом.

В вашем случае, похоже, что каскадирование инициируется дочерними объектами. Когда вы звоните:

$entityManager->remove($section);

Менеджер сущностей замечает только каскадные операции для page, а не для entries.

Когда вы ставите каскадную операцию на Section 's $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;

Вы уверены, что хотите всегда с нетерпением получать все, кстати?

0 голосов
/ 09 марта 2020

Оказывается, что для Doctrine каскадного remove графа сущности-отношения нужно просто аннотировать сторону-владельца следующим образом:

/**
 * 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, что также дало мне ошибки раньше.

...