我对JPA 2.0的orphanRemoval属性有点困惑。
我认为当我使用JPA提供者的DB生成工具创建底层数据库DDL以在特定关系上有一个ON DELETE CASCADE时,我可以看到它是需要的。
但是,如果DB存在并且它已经在关系上有一个ON DELETE级联,这还不足以适当地级联删除吗?孤儿院还做什么?
我对JPA 2.0的orphanRemoval属性有点困惑。
我认为当我使用JPA提供者的DB生成工具创建底层数据库DDL以在特定关系上有一个ON DELETE CASCADE时,我可以看到它是需要的。
但是,如果DB存在并且它已经在关系上有一个ON DELETE级联,这还不足以适当地级联删除吗?孤儿院还做什么?
当前回答
区别在于: - orphanRemoval = true: "Child"实体不再被引用时会被移除(其父实体可能不会被移除)。 ——CascadeType。REMOVE:“Child”实体仅在其“Parent”被删除时才被删除。
其他回答
在以下场景下,孤儿删除与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属性,否则上面的删除代码将不起作用。
这里有一个例子:
当删除Employee实体对象时,删除操作将级联到引用的Address实体对象。在这方面,orphanRemoval=true和cascade=CascadeType。REMOVE是相同的,如果指定orphanremove =true,则CascadeType. REMOVE是相同的。REMOVE是多余的。
这两种设置之间的区别在于断开关系的响应。例如,将地址字段设置为null或另一个address对象。
如果orphanremove =true指定了断开连接的Address实例 自动删除。这对于清除依赖是有用的 对象(例如Address),如果没有引用就不应该存在 所有者对象(例如Employee)。 如果只是cascade=CascadeType。指定了REMOVE,没有自动动作 因为断开一段关系并不意味着移除 操作。
为了避免由于孤立对象移除而导致的悬空引用,应该仅对包含私有非共享依赖对象的字段启用此特性。
我希望这能让你更清楚。
The moment you remove a child entity from the collection you will also be removing that child entity from the DB as well. orphanRemoval also implies that you cannot change parents; if there's a department that has employees, once you remove that employee to put it in another deparment, you will have inadvertantly removed that employee from the DB at flush/commit(whichver comes first). The morale is to set orphanRemoval to true so long as you are certain that children of that parent will not migrate to a different parent throughout their existence. Turning on orphanRemoval also automatically adds REMOVE to cascade list.
@GaryK的答案绝对很棒,我花了一个小时来寻找一个解释orphanRemoval = true vs CascadeType。它帮助我理解。
总结:orphanRemoval = true与CascadeType工作相同。REMOVE ONLY当我们正在删除object (entityManager.delete(object))并且我们希望子对象也被删除时。
在完全不同的情况下,当我们获取一些数据,如List<Child> childs = object.getChilds(),然后使用orphanRemoval=true删除一个子(entityManager.remove(children .get(0)),将导致对应于children .get(0)的实体将从数据库中删除。
orphanRemoval与ON DELETE CASCADE无关。
orphanremove是一个完全特定于orm的东西。当“父”实体不再引用“子”实体时,它标记“子”实体将被删除,例如,当你从父实体的相应集合中删除子实体时。
ON DELETE CASCADE是一个数据库特定的东西,它在删除父行时删除数据库中的“子”行。