Doctrine中cascade={"remove"} 、orphanRemoval=true 和 ondelete="CASCADE" 之间的区别

2019-02-18

我试着收集了一些和 “删除父entity时,子entity也被自动删除” 有关的、应当遵循的信息。最常见的方式是使用以下三种annotation之一:cascade={“remove”},或是 orphanRemoval=true,或是 ondelete=”CASCADE”。

cascade={“remove”}

/**
* @OneToMany(targetEntity="B", mappedBy="A", cascade={"remove"})
*/
protected $B
  • 在ORM体系下实现
  • 应当被用在collection中(因此也在OneToMany或ManyToMany关系中)

如果实体A包含实体B,删除实体A,Doctrine也会删除collection中的所有B实体。
使用此种方法很方便,但也应该小心使用,因为在级联删除中会将对象拖入内存会导致相当大的性能开销,尤其是当级联集合很大时。

比如:你的User有一对多的关系Comment。如果你正在使用cascade=”remove”,您可以从一个User,删除关联的Comment。也可以再之后将Comment附到另一个User上。当你persist他们时,他们将被正确保存。

orphanRemoval=true

/**
* @OneToMany(targetEntity="B", mappedBy="A", orphanRemoval=true)
*/
protected $B
  • 在ORM体系下实现
  • 可以用在 OneToOne、 OnetoMany 或 ManyToMany 中

cascade={"remove"}类似,但也有自己的特点。如果实体A包含对私有实体B的引用,那么如果从中删除引用A,则该实体B也应被删除,因为它不再被使用。
使用orphanRemoval=true选项时,Doctrine假设实体是私有的,也就是不会被其他实体重用。如果您忽略了这个假设,即使您将一个独立出来的实体分配给另一个实体,您的实体也会被Doctrine删除。

比如:你的User有一对多的关系Comment。如果你正在使用cascade=”remove”,您可以从一个User,删除关联的Comment,然后附上Comment到另一个User。当你persist他们时,他们将被正确保存。但是如果您正在使用orphanRemoval=true,即使您从一个User中的删除Comment,然后将其附加到另一个User,此Comment最终还是会在持久化期间被删除,因为该关联已被删除。

ondelete=”CASCADE”

/** 
* @ManyToOne(targetEntity="A", inversedBy="B")
* @JoinColumn(name="A_id", referencedColumnName="A_id", onDelete="CASCADE")
*/ 
protected $A;
  • 由数据库自身管理
  • 这将 “在数据库中”,把 On Delete Cascade(层叠删除) 这一属性,添加到外键所在的字段中。
  • 本策略在运用时有些技巧,但它非常强力且快速。(引自 doctrine官方文档 - 但没有更多解释)
  • ORM 做更少的事(相较前两种方式来说),因此性能占优

更快是因为该操作在数据库层面进行,而非在doctrine中进行。其删除动作由数据库服务器来完成,而不是doctrine。

@2020  TCODE    津ICP备13002520号-4