我对JPA 2.0的orphanRemoval属性有点困惑。

我认为当我使用JPA提供者的DB生成工具创建底层数据库DDL以在特定关系上有一个ON DELETE CASCADE时,我可以看到它是需要的。

但是,如果DB存在并且它已经在关系上有一个ON DELETE级联,这还不足以适当地级联删除吗?孤儿院还做什么?


当前回答

在以下场景下,孤儿删除与ON DELETE CASCADE的效果相同:- . 假设我们在学生实体和指南实体之间有一个简单的多对一关系,其中许多学生可以映射到同一个指南,并且在数据库中,我们在学生和指南表之间有一个外键关系,这样学生表的id_guide为FK。

    @Entity
    @Table(name = "student", catalog = "helloworld")
    public class Student implements java.io.Serializable {
     @Id
     @GeneratedValue(strategy = IDENTITY)
     @Column(name = "id")
     private Integer id;

    @ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE})
    @JoinColumn(name = "id_guide")
    private Guide guide;

//父实体

    @Entity
    @Table(name = "guide", catalog = "helloworld")
    public class Guide implements java.io.Serializable {

/**
 * 
 */
private static final long serialVersionUID = 9017118664546491038L;

@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
private Integer id;

@Column(name = "name", length = 45)
private String name;

@Column(name = "salary", length = 45)
private String salary;


 @OneToMany(mappedBy = "guide", orphanRemoval=true) 
 private Set<Student> students = new  HashSet<Student>(0);

在这种情况下,关系是这样的,学生实体是关系的所有者,因此我们需要保存学生实体,以便持久化整个对象图。

    Guide guide = new Guide("John", "$1500");
    Student s1 = new Student(guide, "Roy","ECE");
    Student s2 = new Student(guide, "Nick", "ECE");
    em.persist(s1);
    em.persist(s2);

在这里,我们用两个不同的学生对象映射同一个指南,并且由于CASCADE。如果使用PERSIST,对象图将被保存在数据库表中(在我的例子中是MySql)

学生表:

ID名称部门Id_Guide

1罗伊·ECE

2尼克ECE

指导表:

工资

1约翰1500美元

现在如果我想删除一个学生,使用

      Student student1 = em.find(Student.class,1);
      em.remove(student1);

当一个学生记录被删除时,相应的指导记录也应该被删除,这就是CASCADE。学生实体中的REMOVE属性出现在图片中,它删除标识符为1的学生以及相应的指导对象(标识符1)。但是在这个例子中,还有一个学生对象映射到相同的指导记录,除非我们在指导实体中使用orphanremove =true属性,否则上面的删除代码将不起作用。

其他回答

DDL ON DELETE CASCADE的等效JPA映射是CASCADE =CascadeType.REMOVE。孤儿删除意味着依赖实体在与其“父”实体的关系被破坏时被删除。例如,如果从@OneToMany关系中删除了一个子对象,而没有显式地在实体管理器中删除它。

区别在于: - orphanRemoval = true: "Child"实体不再被引用时会被移除(其父实体可能不会被移除)。 ——CascadeType。REMOVE:“Child”实体仅在其“Parent”被删除时才被删除。

orphanRemoval与ON DELETE CASCADE无关。

orphanremove是一个完全特定于orm的东西。当“父”实体不再引用“子”实体时,它标记“子”实体将被删除,例如,当你从父实体的相应集合中删除子实体时。

ON DELETE CASCADE是一个数据库特定的东西,它在删除父行时删除数据库中的“子”行。

这里有一个例子:

当删除Employee实体对象时,删除操作将级联到引用的Address实体对象。在这方面,orphanRemoval=true和cascade=CascadeType。REMOVE是相同的,如果指定orphanremove =true,则CascadeType. REMOVE是相同的。REMOVE是多余的。

这两种设置之间的区别在于断开关系的响应。例如,将地址字段设置为null或另一个address对象。

如果orphanremove =true指定了断开连接的Address实例 自动删除。这对于清除依赖是有用的 对象(例如Address),如果没有引用就不应该存在 所有者对象(例如Employee)。 如果只是cascade=CascadeType。指定了REMOVE,没有自动动作 因为断开一段关系并不意味着移除 操作。

为了避免由于孤立对象移除而导致的悬空引用,应该仅对包含私有非共享依赖对象的字段启用此特性。

我希望这能让你更清楚。

实体状态转换

JPA将实体状态转换为SQL语句,如INSERT、UPDATE或DELETE。

当您持久化一个实体时,您将调度INSERT语句在EntityManager被自动或手动刷新时执行。

当您删除一个实体时,您正在调度DELETE语句,该语句将在刷新持久性上下文时执行。

级联实体状态转换

为了方便起见,JPA允许您将实体状态转换从父实体传播到子实体。

所以,如果你有一个父Post实体,它与PostComment子实体有@OneToMany关联:

Post实体中的评论集合映射如下:

@OneToMany(
    mappedBy = "post", 
    cascade = CascadeType.ALL,
    orphanRemoval = true
)
private List<Comment> comments = new ArrayList<>();

CascadeType。所有

cascade属性告诉JPA提供者将实体状态转换从父Post实体传递到注释集合中包含的所有PostComment实体。

所以,如果你移除Post实体:

Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());

entityManager.remove(post);

JPA提供者将首先删除PostComment实体,当所有子实体被删除时,它也将删除Post实体:

DELETE FROM post_comment WHERE id = 1
DELETE FROM post_comment WHERE id = 2

DELETE FROM post WHERE id = 1

孤儿删除

当您将orphanRemoval属性设置为true时,JPA提供者将在从集合中删除子实体时安排一个删除操作。

在我们的例子中,

Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());

PostComment postComment = post.getComments().get(0);
assertEquals(1L, postComment.getId());

post.getComments().remove(postComment);

JPA提供者将删除相关的post_comment记录,因为PostComment实体不再在comments集合中被引用:

DELETE FROM post_comment WHERE id = 1

删除级联

ON DELETE级联定义在FK级别:

ALTER TABLE post_comment 
ADD CONSTRAINT fk_post_comment_post_id 
FOREIGN KEY (post_id) REFERENCES post 
ON DELETE CASCADE;

一旦你这样做了,如果你删除了一个post行:

DELETE FROM post WHERE id = 1

数据库引擎会自动删除所有相关的post_comment实体。但是,如果您错误地删除了根实体,这可能是一个非常危险的操作。

结论

JPA级联和orphanRemoval选项的优点是,您还可以从乐观锁定中受益,以防止丢失更新。

如果您使用JPA级联机制,则不需要使用ddl级别的ON DELETE CASCADE,如果您删除的根实体在多个级别上有许多子实体,那么这可能是一个非常危险的操作。