关于symfony(doctrine)中实体关系的咨询
Consulting about relationship of entities in symfony(doctrine)
我会具体一点。
我有实体任务、城市和组织者。
当我尝试删除管理器时,出现与任务有关的错误
An exception occurred while executing 'DELETE FROM Organizer WHERE id
= ?' with params [522]:
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or
update a parent row: a foreign key constraint fails (test
.Quest
,
CONSTRAINT FK_82D6D713876C4DDA
FOREIGN KEY (organizer_id
)
REFERENCES Organizer
(id
))
我对配置关系的正确方法感到非常困惑。
逻辑是:
- 我们添加了新城市。
- 我们添加了新的组织者并将城市放入组织者。
- 我们创建新的任务,然后将城市和组织者放入其中。
- 如果我们删除组织者 - 任务中的组织者 ID 必须是
移除(任务不得移除)。
- 如果我们删除组织者 - 并且必须删除城市中的组织者 ID
也是(并且不能删除城市)。
很抱歉我的描述很愚蠢,但我试图排除误解。
嗯,对于我的情况,我应该使用什么正确的实体关系?
class Quest {
...
/**
* @ORM\JoinColumn(name="organizer_id", referencedColumnName="id")
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Organizer")
*/
protected $organizer;
}
class Organizer {
...
/**
* @ORM\Column(type="string", length=140)
*/
protected $name;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\City", inversedBy="organizers")
* @ORM\JoinTable(name="organizers_cities")
*/
protected $cities;
public function __construct() {
$this->quests = new ArrayCollection(); // i don't remember why this is here
}
}
class City {
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Organizer", mappedBy="cities")
*/
protected $organizers;
/**
* Constructor
*/
public function __construct() {
$this->quests = new \Doctrine\Common\Collections\ArrayCollection();
$this->organizers = new \Doctrine\Common\Collections\ArrayCollection();
}
}
问题很简单,您无法删除组织者,因为它已被现有任务引用。在您的情况下,您必须首先删除关系。我不知道用 doctrine 自动执行此操作的方法,但您可以在 preRemove 事件中配置一个事件侦听器,并将 Quest organizer 字段设置为 null。我不确定 symfony 2.1 中是否实现了事件侦听器,但我希望如此。您还可以选择在 remove 调用之前直接在控制器中执行 null 关系。同样的情况也适用于城市。检查此文档链接:
How to Register Event Listeners and Subscribers
希望对您有所帮助。
您必须配置 Doctrine 或您的数据库以将关系设置为空。
有了学说,只需删除您的实体即可:
$em=$this->getDoctrine()->getEntityManager(); // or getManager() in current Doctrine versions.
$em->remove($organizer);
$em->flush();
与您的数据库:
更改您的 JoinColumn 注释:
class Quest {
...
/**
* @ORM\JoinColumn(nullable=false, onDelete="SET NULL",name="organizer_id", referencedColumnName="id")
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Organizer")
*/
protected $organizer;
}
通过第二种方法,您将能够使用 DQL 查询。
此方法绕道主义,首选第一种
我忘记了两件重要的事情。
- 学说生命周期事件
- php bin/console doctrine:generate:entities
AppBundle/Entity/Quest 将只生成常用方法。 (有
没有 removeOrganizer() 函数 )
所以,解决方案很简单,但是......见下文。
class Quest {
...
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Organizer", inversedBy="quests")
* @ORM\JoinColumn(name="organizer_id", referencedColumnName="id")
*/
protected $organizer;
...
public function removeOrganizer()
{
$this->organizer = null;
return $this;
}
public function removeCity()
{
$this->city = null;
return $this;
}
}
class Organizer {
...
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\City", inversedBy="organizers")
*/
protected $cities;
/**
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Quest", mappedBy="organizer"))
*/
protected $quests;
public function __construct() {
$this->quests = new ArrayCollection();
}
...
/**
* @ORM\PreRemove()
*/
public function removeRelationWithQuests() {
foreach($this->getQuests() as $quest) {
$quest->removeOrganizer()
->setStatus(0);
}
}
}
class City {
...
/**
* @OneToMany(targetEntity="AppBundle\Entity\Quest", mappedBy="city"))
*/
protected $quests;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Organizer", mappedBy="cities")
*/
protected $organizers;
...
/**
* @ORM\PreRemove()
*/
public function removeRelationWithQuests() {
foreach($this->getQuests() as $quest) {
$quest->removeCity()
->setStatus(0);
}
}
}
如您所见,我为任务实体添加了新函数 removeOrganizer 和 removeCity,并将其与 City 和 Organizer 实体中的事件 preRemove 一起使用。
PS 我相信有更好的实践来解决这样的任务。所以,我愿意为你接受批评。
我会具体一点。 我有实体任务、城市和组织者。 当我尝试删除管理器时,出现与任务有关的错误
An exception occurred while executing 'DELETE FROM Organizer WHERE id = ?' with params [522]:
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (
test
.Quest
, CONSTRAINTFK_82D6D713876C4DDA
FOREIGN KEY (organizer_id
) REFERENCESOrganizer
(id
))
我对配置关系的正确方法感到非常困惑。 逻辑是:
- 我们添加了新城市。
- 我们添加了新的组织者并将城市放入组织者。
- 我们创建新的任务,然后将城市和组织者放入其中。
- 如果我们删除组织者 - 任务中的组织者 ID 必须是 移除(任务不得移除)。
- 如果我们删除组织者 - 并且必须删除城市中的组织者 ID 也是(并且不能删除城市)。
很抱歉我的描述很愚蠢,但我试图排除误解。
嗯,对于我的情况,我应该使用什么正确的实体关系?
class Quest {
...
/**
* @ORM\JoinColumn(name="organizer_id", referencedColumnName="id")
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Organizer")
*/
protected $organizer;
}
class Organizer {
...
/**
* @ORM\Column(type="string", length=140)
*/
protected $name;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\City", inversedBy="organizers")
* @ORM\JoinTable(name="organizers_cities")
*/
protected $cities;
public function __construct() {
$this->quests = new ArrayCollection(); // i don't remember why this is here
}
}
class City {
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Organizer", mappedBy="cities")
*/
protected $organizers;
/**
* Constructor
*/
public function __construct() {
$this->quests = new \Doctrine\Common\Collections\ArrayCollection();
$this->organizers = new \Doctrine\Common\Collections\ArrayCollection();
}
}
问题很简单,您无法删除组织者,因为它已被现有任务引用。在您的情况下,您必须首先删除关系。我不知道用 doctrine 自动执行此操作的方法,但您可以在 preRemove 事件中配置一个事件侦听器,并将 Quest organizer 字段设置为 null。我不确定 symfony 2.1 中是否实现了事件侦听器,但我希望如此。您还可以选择在 remove 调用之前直接在控制器中执行 null 关系。同样的情况也适用于城市。检查此文档链接:
How to Register Event Listeners and Subscribers
希望对您有所帮助。
您必须配置 Doctrine 或您的数据库以将关系设置为空。
有了学说,只需删除您的实体即可:
$em=$this->getDoctrine()->getEntityManager(); // or getManager() in current Doctrine versions. $em->remove($organizer); $em->flush();
与您的数据库:
更改您的 JoinColumn 注释:
class Quest { ... /** * @ORM\JoinColumn(nullable=false, onDelete="SET NULL",name="organizer_id", referencedColumnName="id") * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Organizer") */ protected $organizer; }
通过第二种方法,您将能够使用 DQL 查询。 此方法绕道主义,首选第一种
我忘记了两件重要的事情。
- 学说生命周期事件
- php bin/console doctrine:generate:entities AppBundle/Entity/Quest 将只生成常用方法。 (有 没有 removeOrganizer() 函数 )
所以,解决方案很简单,但是......见下文。
class Quest {
...
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Organizer", inversedBy="quests")
* @ORM\JoinColumn(name="organizer_id", referencedColumnName="id")
*/
protected $organizer;
...
public function removeOrganizer()
{
$this->organizer = null;
return $this;
}
public function removeCity()
{
$this->city = null;
return $this;
}
}
class Organizer {
...
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\City", inversedBy="organizers")
*/
protected $cities;
/**
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Quest", mappedBy="organizer"))
*/
protected $quests;
public function __construct() {
$this->quests = new ArrayCollection();
}
...
/**
* @ORM\PreRemove()
*/
public function removeRelationWithQuests() {
foreach($this->getQuests() as $quest) {
$quest->removeOrganizer()
->setStatus(0);
}
}
}
class City {
...
/**
* @OneToMany(targetEntity="AppBundle\Entity\Quest", mappedBy="city"))
*/
protected $quests;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Organizer", mappedBy="cities")
*/
protected $organizers;
...
/**
* @ORM\PreRemove()
*/
public function removeRelationWithQuests() {
foreach($this->getQuests() as $quest) {
$quest->removeCity()
->setStatus(0);
}
}
}
如您所见,我为任务实体添加了新函数 removeOrganizer 和 removeCity,并将其与 City 和 Organizer 实体中的事件 preRemove 一起使用。
PS 我相信有更好的实践来解决这样的任务。所以,我愿意为你接受批评。