原则:一对多级联中的异常:违反完整性约束 1451
Doctrine: Exception in One-To-Many cascading: Integrity constraint violation 1451
我正在尝试使用 Symfony
和 Doctrine
构建一个非常基本的 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;
您确定要始终急切地获取所有内容吗?
事实证明,为了 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
手动删除条目,这之前也给了我错误。
我正在尝试使用 Symfony
和 Doctrine
构建一个非常基本的 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;
您确定要始终急切地获取所有内容吗?
事实证明,为了 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
手动删除条目,这之前也给了我错误。