【JPA 级联保存/级联删除】@OneToMany (双向) 一对多【转】

【http://blog.sina.com.cn/s/blog_625d79410101dbdd.html】

看过前两篇帮助文档 【JPA】 @OneToOne 单向 和 【JPA】@OneToOne 双向 想必大家对级联操作已经充满了好奇和期待吧。那么本文将会想大家介绍JPA的级联保存操作。在此之前,我希望你能先看下这篇文档,对级联注释的各个属性有一个大概的了解。传送门:【JPA】 级联标签的解释 @Cascade

在生活中,有许多关系都是一对多的。School(学校)和 Studnet(学生) 之间的关系就是典型的一对多关系。一所学校,有多名学生。但是一个学生,只能属于一所学校。在这里,我们将这个关系设置为一个双向的关系。也就说,通过学生实体,我们可以得到他就读的学校的实体。同样,通过一个学校实体,我们也可一得到在这所学校就读的学生实体的集合。

--------< 例 子 >----------------------------------------------------------------------------------------------------------

//学生Model , 这个双向一对多关系的维护端。一般来说,在双向一对多关系中,"多"这一端,一般都是关系的维护端。

@Entity

@Table(name = "student")

public class Student {

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

private Long id;

//在表中建立外键 "school_fk"

@ManyToOne

@JoinColumn(name="school_fk")

private School school;

//省略若干get / set

}

@Entity

@Table(name = "school")

public class School {

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

private Long id;

@OneToMany(mappedBy="shcool")

//设置 :级联 保存/新建 操作 。新建 学校和学生 的时候,保存新建的学校那么新建的学生也同时被保存

@Column(cascade={CascadeType.PERSIST})

private List students;

//手动构造添加学生的方法

public void addStudent(Strudent stu){

if(stu != null){

students.add(stu);

}

}

//省略若干get / set

}

-----------------------------------------------------< 测试方法 >--------------------------------------------------------------

public class Test(){

public void testCreate(){

School school = new School();

school.setName("学校");

Student st1 = new Student();

st1.setName("学弟");

st1.setSchool(school);

studnetDAO.save(st1);

Student st2 = new Student();

st2.setName("学长");

st2.setSchool(school);

studnetDAO.save(st2);

//添加学生

school.addStudent(st1);

school.addStudent(st2);

schoolDAO.save(school);

//以上的保存方法并不是级联保存操作。我们在学校实体上设置了,级联保存操作。

//我们希望JPA这样做,在新建学校,新建多名学生时。只要将学生的所属学校设置完成后,保存学校,即可保存 所属该校的学生。

}

//级联保存,测试方法

public void testPersistCreateSchool(){

//级联保存演示:已经在学校(School)Model 中添加了 级联保存操作:cascade={CascadeType.PERSIST}

School school = new School();

school.setName("学校");

Student st1 = new Student();

st1.setName("学弟");

st1.setSchool(school);

//  不需要显示保存学生 st1

//studnetDAO.save(st1);

Student st2 = new Student();

st2.setName("学长");

st2.setSchool(school);

//  不需要显示保存学生 st2

//studnetDAO.save(st2);

//添加学生

school.addStudent(st1);

school.addStudent(st2);

schoolDAO.save(school);// 保存学校,学校内新建的学生也[st1、st2]被保存了。(级联保存)

}

//测试删除

public void testDeleteSchool(){

//革命第一步,创建学校。

testCreate();

schoolDAO.delete(school);//后台报错

//avax.persistence.RollbackException: Error while commiting the transaction Caused by: java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint...

//之前我们已经知道,想要删除关系的被维护端,必须先从维护端解除关系。才能正常删除。所以我们要做的就是,先从 学生端,解除关系。

List<Strudnet> students = school.getStudentList();

for(int i=0;i<students.size();i++){

Student stu = students.get(i);

stu.setSchool(null);//手动从学生实体解除挂系

}

schoolDAO.delete(school);//现在,学校被正常的删除了。该校的两名学生信息依然保存在数据库中。只是,他们没有所属学校了。

//看到这里,你一定会责备我。JPA不是很强大么?不是很灵活多变么?不是很神奇么?

//为什么删除一个实体,还需要循环解除关系,这么繁琐的操作?!

//其实,我们有方法可以直接删除学校。并且,不需要进行这种循环从学生实体解除关系的操作。但是,相信我,这种方法你可能不会接受。下面,就让我们来看看JPA的级联删除。

//修改学校的Model 中,在校生字段()的注释:@Column(cascade={CascadeType.PERSIST})

//改为:@Column(cascade={CascadeType.PERSIST,CascadeType.REMOVE}) 添加级联删除操作。那么,现在你就可以直接调用删除学校的方法了。

schoolDAO.delete(school);//现在,学校也被正常删除了。但是,接下来的一幕,你可能不愿意看到。

Stduent stu = studentDAO.findByName(学长");

//打印的结果为: null   是的,你没看错。该校所有的学生也被级联删除了...

//此时,你应该对JPA的级联删除有所理解了。它删除的对象是实体。级联指的是级联实体。如果,在学生的Model 中添加了一个级联删除的操作,那么删除一个学生,那这个学生所属的学校也会被删除掉。

//所以,在这里,我要提醒你。级联的删除操作要慎用。因为,他的破坏性太大了。级联删除的操作,并不是针对某个字段,而是它所管理的实体。

}

//测试删除

public void testDeleteStudent(){

//创建学校和学生

testCreate();

studentDAO.delete(st1);//此时,st1(创建时,名字叫“学弟”的学生)已经被从数据库中删除了。但是,他所属的学校并没受影响。只不过,st1已经从 学校的 学生集合里删除了。这都是由JPA来完成的。

//现在,我们假设:我们没有执行刚才那部。st1没有被删除。学校依然拥有两名学生。

//在,Stuent的Model 中添加级联删除的操作。@JoinColumn(name="school_fk",cascade={CascadeType.REMOVE})   并且,School 的 Model中也添加级联删除的操作。

//此时,数据库中,只有一所学校和两名学生的信息。

studentDAO.delete(st1);

//哇,全世界都干净了。如果这个时候查看数据库。你会发现,所有的数据都没了。为什么会这样呢?

//让我们来看看JPA都干了什么:

1:删除 st1

2:school 被 st1 级联删除

3:st2 被 school 级联删除

//所以,你才会发现,数据库中所有的信息都消失了。当然,如果之前,数据库中还有别的学校和别的学校所属学生。那么它们的信息是不受影响的。

//罗嗦了这么多,我感到很抱歉。我只是想提醒你,一定要慎用这个级联的删除操作。千万不用在建立Model 的时候,顺手添加一个级联保存 删除之类的操作。一定要根据自己的需求。和操作的实际效果,仔细斟酌之后,再付诸于行动。否则,你直接来个CascadeType.ALL 大多数情况下,它带给你的都是痛苦的回忆。

}

//省略main 方法

}

时间: 2024-10-13 07:53:16

【JPA 级联保存/级联删除】@OneToMany (双向) 一对多【转】的相关文章

JPA双向一对多多一对一

? 双向一对多关系中,必须存在一个关系维护端,在 JPA 规范中,要求  many 的一方作为关系的维护端(owner side), one 的一方作为被维护端(inverse side). ?可以在 one 方指定 @OneToMany 注释并设置 mappedBy 属性,以指定它是这一关联中的被维护端,many 为维护端. ?在 many 方指定 @ManyToOne 注释,并使用 @JoinColumn 指定外键名称 package com.morris.entity; import ja

jpa 双向一对多,多对一关联关系

1.1.  双向一对多 Order.java package com.morris.entity; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.Id; import ja

级联保存

可以主表级联多表,也可以多表级联主表,原理是一样的,主要的就是xml的配置上面: cascade="save-update"要加上 主表的xml: 1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC 3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 "

ManytOone的级联保存

(1)在many方(如user)添加指向one方(如group)的引用即在user类中增加“ private Group group;”,并生成geter和seter.(2)在geter上添加注解@ManyToOne.@JoinColumn(name="groupId")其中groupId表示生成表的外键名.(3)编写测试程序1)得到Configuration,生成SchemaExport ,在数据库中建立表(如果已存在,立即删除)2)新建Group对象和多个user对象,并设置use

hibernate级联保存,更新个人遇到的问题

在级联更新的时候,数据库中的数据是增加的,只是外键不存在,导致这样的问题产生的原因是,字表主键ID没有添加到集合中,导致Hibernate找不到子项而执行更新. hibernate级联保存,更新个人遇到的问题,布布扣,bubuko.com

SQL图形化操作设置级联更新和删除

SQL级联操作设置 对SQL数据库的表,进行级联操作(如级联更新及删除),首先需要设置表的主外键关系,有两种方法: 第一种: 1. 选择你要进行操作的数据库 2. 为你要创建关系的两个表设置主键 3. 在此数据库的数据库关系图一栏处 =>单击右键=>创建新的关系图=>选择要添加关系的表,单击添加 4. 完成后会在关系图的窗口上生成两个表,在表的某列按钮上长按鼠标左键,并拖到另一张表上 5. 在新弹出的"表和列"的窗口中,设置两个表对应的主外键字段,确定 6. 在外键关

hibernate级联保存问题

今天的遇到一个问题,搞了半天.做个记录 hibernate级联保存,设置了cascade关系,但新增时总是主表insert,从表update.以下为报错信息: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1 网上的解释是id冲突导致的,即数据库中定义了id自增,而类被插入时也被赋予了id. 解决办法:将数据库id自增去掉,重新生成类文件,选择id自增策略选择i

8、双向一对多的关联关系(等同于双向多对一。1的一方有对n的一方的集合的引用,同时n的一方有对1的一方的引用)

双向一对多关联关系 ”双向一对多关联关系“等同于”双向多对一关联关系“:1的一方有对n的一方的集合的引用,同时n的一方有对1的一方的引用. 还是用客户Customer和订单Order来解释: ”一对多“的物理意义:一个客户可以有多个订单,某个订单只能归宿于一个客户. ”双向“的物理意义:客户知道自己有哪些订单,订单也知道自己归宿于哪个客户.也就是说,通过客户对象可以检索到其拥有哪些订单:同时,通过订单也可以查找到其对应的客户信息.这是符合我们业务逻辑需求. 到现在为止(结合前面两节的阐述)我们可

Hibernate实现双向一对多,多对一

人与电话号码是一对多 ,多对一的关系 @Entity @Table(name="tb_person") public class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; private String name; @OneToMany(mappedBy = "person") /*在双向一对多关系中 将控制权交给“多”方 */ private List&l