在我的模特中我有
/**
* @ORM\Entity
* @ORM\HasLifecycleCallbacks()
*/
class Terrain
{
/**
* @var lots
*
* @ORM\OneToMany(targetEntity="Lot", mappedBy="terrain")
*/
private $lotes;
/**
* @ORM\PreRemove
*/
public function deleteAllLots()
{
$lots = $this->getLots();
foreach ($lots as $lot) {
$this->lots->removeElement($lot);
}
}
}
/**
* @ORM\Entity
* @ORM\HasLifecycleCallbacks()
*/
class Lot
{
/**
* @var Terrain
*
* @ORM\ManyToOne(targetEntity="Terrain", inversedBy="lots")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="terrain_id", referencedColumnName="id")
* })
*/
var $terrain
}
拍
我正在尝试删除地形,但之前我删除了与之相关的所有地段。当我尝试删除地形时,我收到错误SQLSTATE[23000]: Integrity constraint violation
答案 0 :(得分:9)
您在删除时仍然有lots
到terrain
的引用,这就是您拥有Integrity constrait violation
的原因。
试试这个:
/**
* @ORM\Entity
* @ORM\HasLifecycleCallbacks()
*/
class Terrain
{
/**
* @var lots
*
* @ORM\OneToMany(targetEntity="Lot", mappedBy="terrain")
*/
private $lotes;
/**
* @ORM\PreRemove
*/
public function deleteAllLots()
{
$lots = $this->getLots();
foreach ($lots as $lot) {
$this->lots->removeElement($lot);
$lot->terrain = null; //$lot->setTerrain(null); will be better, try to add getters and setters
}
}
}
如果要从数据库中删除lots
,则应使用cascade
关系(One-To-Many reference on doctrine-project.com)的OneToMany
属性,如下所示:
/**
* @ORM\Entity
* @ORM\HasLifecycleCallbacks()
*/
class Terrain
{
/**
* @var lots
*
* @ORM\OneToMany(targetEntity="Lot", mappedBy="terrain", cascade={"remove"})
*/
private $lotes;
}
在Terrain
删除后,将删除所有批次。
答案 1 :(得分:1)
发布的第一个代码here也不会删除第二个表中的数据,它只是使引用为空,如果你只依赖一个实体,通常不应该为null(你不应该有任何实体)在该表中没有任何引用的旧行,因为在大多数情况下,您无法使用它们,它只会使该表中包含您不需要的内容并且使您的索引变得棘手)。
生命周期回调是触发事件时调用的实体类的方法。它们绝对不接受任何参数,并且专门设计为允许实体类状态内的更改。 生命周期事件监听器是具有特定回调方法的类,它们接收某种类型的EventArgs实例,该实例可以访问实体,EntityManager或其他相关数据。
生命周期回调仅用于更改该实体,而不是其所引用的其他实体。 您必须使用Lifecycle Event Listener而不是Lifecycle Callback。 使用Lifecycle Event Listener,您可以访问实体管理器并删除这些实体。 但是正确的方法是在引用上使用delete cascade,这样,doctrine可以忽略引用的对象(不必从数据库中读取它们只是为了以后删除它们1)并让数据库处理它们。 你应该改变这一行:
@ORM\JoinColumn(name="terrain_id", referencedColumnName="id")
到这个
@ORM\JoinColumn(name="terrain_id", referencedColumnName="id", onDelete="cascade")
您可以在JoinColumn注释here找到文档。
您可以按照建议的here对OneToMany
注释使用cascade =“remove”参数,但速度要慢得多。
答案 2 :(得分:0)
为什么不使用PostRemove而不是PreRemove?此方法允许您在批次之后删除Terrain而不会违反数据库完整性。删除Lots后,现在您可以安全地删除相关的Terrain。
/**
* @ORM\PostRemove
*/
public function deleteTerrain(\Doctrine\ORM\Event\LifecycleEventArgs $args)
{
$em = $args->getEntityManager();
$terrain = $this->getTerrain();
$em->remove($terrain);
$em->flush();
}