hibernate练习之双向关联一对多
2014-09-03 10:11
369 查看
实体类:
一个班级对应多个学生,一个学生对应一个班级。
一的一方为班级,多的一方为学生,在多的一方设置外键(也就是在多的一方的实体类中写一的一方的引用),在一的一方实体类中写集合,集合中的元素为多的一方。
在映射文件中多的一方配置<many-to-one>标签,在一的一方配置集合,
如 <set name="students" cascade="all" inverse="false">
<key>
<!--
通过classes建立与student之间的联系
-->
<column name="cid"></column>
</key>
<one-to-many class="com.oneToMany.Student"/>
</set>
班级的实体类:Classes
映射文件:
班级的映射文件:
学生的映射文件:
配置文件:hibernate.cfg.xml
利用Junit进行测试
一对多的操作:
* hibernate是通过客户端的代码参照映射文件来决定怎么样去数据库进行操作
* 一对多的双向:既能通过Classes.hbm.xml文件联系到student,也能通过student.hbm.xml文件联系到
classes,在类中也要体现双向的关系
* session.save/update(classes),hibernate内部会参照classes.hbm.xml文件,这个时候student.hbm.xml
映射文件不起作用,反之也成立
* 在hibernate一对多的关系中,只有一的一端的set集合中有inverse属性,多的一端没有inverse属性
* 在hibernate中,inverse属性和数据库的外键对应
* 在Classes.hbm.xml文件中,set集合,inverse的值如果为true,说明classes放弃关系的维护,如果为false,
则负责维护关系,但是多的一方维护关系效率比较高
* cascade说明指的是对象与对象之间的操作,和外键没有关系
* 处于持久化状态的对象在session中,在客户端不需要做session.save/update操作,hiernate内部会自动去检查
持久化状态的对象的属性是否发生改变,如果改变则发出update语句,如果没有改变则不会发出update语句。如果
该对象是一的一方,在一的一方的映射文件中有cascade="all"时,hibernate内部还会检查该持久化对象关联的
集合,对此集合做update/save操作。但是整个操作和外键没有关系。只有当通过多的一方建立关系以后,才能使
外键有值
* 一般一对多设计到关系的维护,都是通过多的一方来操作的
一个班级对应多个学生,一个学生对应一个班级。
一的一方为班级,多的一方为学生,在多的一方设置外键(也就是在多的一方的实体类中写一的一方的引用),在一的一方实体类中写集合,集合中的元素为多的一方。
在映射文件中多的一方配置<many-to-one>标签,在一的一方配置集合,
如 <set name="students" cascade="all" inverse="false">
<key>
<!--
通过classes建立与student之间的联系
-->
<column name="cid"></column>
</key>
<one-to-many class="com.oneToMany.Student"/>
</set>
班级的实体类:Classes
package com.oneToMany; import java.io.Serializable; import java.util.Set; public class Classes implements Serializable{ private Long cid; private String cname; private String description; private Set<Student> students;//一的一方写集合(因为含有多个相同的) public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Long getCid() { return cid; } public void setCid(Long cid) { this.cid = cid; } public String getCname() { return cname; } public void setCname(String cname) { this.cname = cname; } public Set<Student> getStudents() { return students; } public void setStudents(Set<Student> students) { this.students = students; } }学生的实体类:
package com.oneToMany; import java.io.Serializable; public class Student implements Serializable{ private Long sid; private String sname; private Classes classes;//多的一方写 一的一方的引用(也就是定义一个一的一方的类变量) public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } private String description; public Long getSid() { return sid; } public void setSid(Long sid) { this.sid = sid; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public Classes getClasses() { return classes; } public void setClasses(Classes classes) { this.classes = classes; } }
映射文件:
班级的映射文件:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Mapping file autogenerated by MyEclipse Persistence Tools --> <hibernate-mapping> <class name="com.oneToMany.Classes"> <id name="cid" type="java.lang.Long" length="5"> <column name="cid"></column> <generator class="increment"></generator> </id> <property name="cname" type="java.lang.String" length="20"></property> <property name="description" type="java.lang.String" length="100"></property> <!-- cascade指的是对象对对象的操作 inverse指的是对象对关系的操作 inverse是用来维护关系的 * 要么是一对多的关系 * 要么多对多的关系 * 谁来维护关系 inverse所在的映射文件对应的持久化对象维护关系 默认值是false 表明维护关系 true 表明不维护关系 --> <set name="students" cascade="all" inverse="false"> <key> <!-- 通过classes建立与student之间的联系 --> <column name="cid"></column> </key> <one-to-many class="com.oneToMany.Student"/> </set> </class> </hibernate-mapping>
学生的映射文件:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Mapping file autogenerated by MyEclipse Persistence Tools --> <hibernate-mapping> <class name="com.oneToMany.Student"> <id name="sid" type="java.lang.Long" length="5"> <column name="sid"></column> <generator class="increment"></generator> </id> <property name="sname" type="java.lang.String" length="20"></property> <property name="description" type="java.lang.String" length="100"></property> <!-- 多对一 注意:在many-to-one中没有inverse属性 对student表的修改本身就是维护外键 --> <many-to-one name="classes" class="com.oneToMany.Classes" cascade="all"> <!-- 外键 描述了通过student建立与classes之间的联系 --> <column name="cid"></column> </many-to-one> </class> </hibernate-mapping>
配置文件:hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <!-- 是用来描述数据库的连接 --> <session-factory> <!-- 驱动 --> <property name="connection.driver_class"> com.mysql.jdbc.Driver </property> <!-- url --> <property name="connection.url"> jdbc:mysql://localhost:3306/hibernate </property> <!-- username --> <property name="connection.username">root</property> <!-- password --> <property name="connection.password">root</property> <!-- hibernate针对建表的操作 update 如果有表,检查表的结构,如果没有则创建 create-drop 启动hibernate创建表,结束hibernate删除表 create 每次启动都重新创建表 validate 每次启动都检查表的结构 --> <property name="hbm2ddl.auto">update</property> <property name="show_sql">true</property> <mapping resource="com/oneToMany/Classes.hbm.xml" /> <mapping resource="com/oneToMany/Student.hbm.xml" /> </session-factory> </hibernate-configuration>
利用Junit进行测试
package com.oneToMany; import java.util.HashSet; import java.util.List; import java.util.Set; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; /** * 1、保存班级 * 2、保存学生 * 3、保存班级的时候同时保存学生 * 4、保存班级的时候同时保存学生,并且建立班级和学生之间的关系 * 5、已经存在一个班级,新建一个学生,并且建立该学生和该班级之间的关系 * 6、已经存在一个学生,新建一个班级,并且建立该学生和该班级之间的关系 * 7、已经存在一个学生,已经存在一个班级,解除该学生和原来班级之间的关系,建立该学生和新班级之间的关系 * 8、已经存在一个学生,解除该学生和该学生所在班级之间的关系 * 9、解除该班级和所有的学生之间的关系,再重新建立该班级和一些新的学员之间的关系 * 10、解除该班级和所有的学生之间的关系 * 11、删除班级 * * * * 解除该班级和所有的学生之间的关系 * * 删除该班级 * * * 删除班级的同时删除学生 * 12、删除学生 * 同删除班级 * @author Administrator * */ public class OneToManyDoubleTest { private static SessionFactory sf= null; static{ Configuration configuration = new Configuration();//获取Configuration实例 configuration.configure("com/oneToMany/hibernate.cfg.xml");//加载指定路径下的配置文件 sf = configuration.buildSessionFactory();//创建一个session工厂,利用工厂产生session } /* 加载方式2 SessionFactory sf = new Configuration().configure() .addClass(Classes.class) .addClass(Student.class) .buildSessionFactory();*/ /** * 3、保存班级的时候同时保存学生 * Hibernate: select max(cid) from Classes Hibernate: select max(sid) from Student Hibernate: insert into Classes (cname, description, cid) values (?, ?, ?) Hibernate: insert into Student (sname, description, cid, sid) values (?, ?, ?, ?) Hibernate: update Student set cid=? where sid=? 更新外键 说明: classes.setStudents(students); 通过classes来维护关系 ,要发出update语句,更新外键 */ @Test public void testSaveClasses_Cascade_S(){ Session session = sf.openSession(); session.beginTransaction(); Classes classes = new Classes(); classes.setCname("计科1"); Student stu = new Student(); stu.setSname("张2"); Set<Student> students = new HashSet<Student>(); students.add(stu); // classes.setStudents(students); stu.setClasses(classes); session.save(classes); session.getTransaction().commit(); session.close(); } /** * 已经存在一个班级,新建一个学生,并且建立该学生和该班级之间的关系 */ @Test public void testSaveStudent_R(){ Session session = sf.openSession(); session.beginTransaction(); //通过班级关联学生 //取出班级 /*Classes classes = (Classes) session.get(Classes.class, 1L); //新建一个学生 Student stu = new Student(); stu.setSname("张三"); //建立学生和班级之间的关系 classes.getStudents().add(stu);*/ //通过学生关联班级 Classes classes = (Classes) session.get(Classes.class, 2L); Student stu = new Student(); stu.setSname("张四"); stu.setDescription("好哥们"); stu.setClasses(classes); session.save(stu); session.getTransaction().commit(); session.close(); } /** * 已经存在一个学生,新建一个班级,并且建立该学生和该班级之间的关系 * 通过分析: * * 因为存在建立关系的操作,所以操作学生端效率比较高 * * 在这里存在保存班级的操作,所以应该是通过更新学生级联保存班级 * 可以通过学生和班级建立关联关系,也可以通过班级和学生建立关联关系 */ @Test public void testUpdateStudent_CasCade(){ Session session = sf.openSession(); session.beginTransaction(); //获取一个学生 Student stu = (Student) session.get(Student.class, 2L); Classes classes = new Classes(); classes.setCname("一般"); classes.setDescription("不错"); /* Set<Student> students = new HashSet<Student>(); students.add(stu); classes.setStudents(students);*/ //stu.setClasses(classes); session.save(classes); session.getTransaction().commit(); session.close(); } /** * 已经存在一个学生,已经存在一个班级,解除该学生和原来班级之间的关系,建立该学生和新班级之间的关系 */ @Test public void testRebuild_R(){ Session session = sf.openSession(); session.beginTransaction(); Student stu = (Student) session.get(Student.class, 1L); Classes classes = (Classes) session.get(Classes.class, 2L); //因为sutdent已经是持久化类,所以可以不调用save方法 stu.setClasses(classes); session.getTransaction().commit(); session.close(); } /** * 已经存在一个学生,解除该学生和该学生所在班级之间的关系 */ @Test public void testRealse_R(){ Session session = sf.openSession(); Transaction transaction = session.beginTransaction(); Student student = (Student)session.get(Student.class, 2L); student.setClasses(null); transaction.commit(); session.close(); } /** * 解除该班级和所有的学生之间的关系,再重新建立该班级和一些新的学员之间的关系 */ @Test public void testRealse_Rebuild_R(){ Session session = sf.openSession(); session.beginTransaction(); Student stu1 = new Student(); stu1.setSname("新学员1"); Student stu2 = new Student(); stu2.setSname("新学员2"); /* 查询出在班级中的学生,并移出集合的做法 Classes classes = (Classes) session.get(Classes.class, 2L); List list = session.createQuery("from Student where sid in(1,3)").list(); classes.getStudents().removeAll(list); classes.getStudents().add(stu1); classes.getStudents().add(stu2);*/ /** * 1、获取班级 * 2、获取该班级的所有的学生 * 3、遍历学生,把学生的班级设置为null * 4、新建两个学员 * 5、建立两个学员与班级之间的关系 */ Classes classes = (Classes) session.get(Classes.class, 2L); Set<Student> students = classes.getStudents(); for(Student stu:students){//迭代并将所有的学生与该班级解除关系 stu.setClasses(null); } students.add(stu1); students.add(stu2); /** * 当发生transaction.commit的时候,hibernate内部会检查所有的持久化对象 * 会对持久化对象做一个更新,因为classes是一个持久化状态的对象,所以hibernate * 内部要对classes进行更新,因为在classes.hbm.xml文件中<set name="students" cascade="all" inverse="true"> * 意味着在更新classes的时候,要级联操作student,而student是一个临时状态的对象 * 所以要对student进行保存,在保存student的时候,就把外键更新了 */ session.getTransaction().commit(); session.close(); } /** * 解除该班级和所有的学生之间的关系 */ @Test public void testRealseAll_R(){ Session session = sf.openSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 1L); Set<Student> students = classes.getStudents(); for(Student student:students){ student.setClasses(null); } transaction.commit(); session.close(); } /** * 先解除关系,再删除班级 */ @Test public void testDeleteClass_1(){ Session session = sf.openSession(); session.beginTransaction(); Classes classes = (Classes) session.get(Classes.class, 2L); Set<Student> students = classes.getStudents(); for(Student stu:students){//迭代将和与该班级所有的学生设置为null,即解除关系 stu.setClasses(null); } session.delete(classes);//删除班级 session.getTransaction().commit(); session.close(); } /** * 在删除班级的时候,同时删除整个班级的学生 */ @Test public void teetDeleteClass(){ Session session = sf.openSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 7L); session.delete(classes); transaction.commit(); session.close(); } //12、删除学生 同删除该学生所在班级 @Test public void teetDeleteStudent(){ Session session = sf.openSession(); session.beginTransaction(); Student stu = (Student) session.get(Student.class, 1L); session.delete(stu); session.getTransaction().commit(); session.close(); } }总结:
一对多的操作:
* hibernate是通过客户端的代码参照映射文件来决定怎么样去数据库进行操作
* 一对多的双向:既能通过Classes.hbm.xml文件联系到student,也能通过student.hbm.xml文件联系到
classes,在类中也要体现双向的关系
* session.save/update(classes),hibernate内部会参照classes.hbm.xml文件,这个时候student.hbm.xml
映射文件不起作用,反之也成立
* 在hibernate一对多的关系中,只有一的一端的set集合中有inverse属性,多的一端没有inverse属性
* 在hibernate中,inverse属性和数据库的外键对应
* 在Classes.hbm.xml文件中,set集合,inverse的值如果为true,说明classes放弃关系的维护,如果为false,
则负责维护关系,但是多的一方维护关系效率比较高
* cascade说明指的是对象与对象之间的操作,和外键没有关系
* 处于持久化状态的对象在session中,在客户端不需要做session.save/update操作,hiernate内部会自动去检查
持久化状态的对象的属性是否发生改变,如果改变则发出update语句,如果没有改变则不会发出update语句。如果
该对象是一的一方,在一的一方的映射文件中有cascade="all"时,hibernate内部还会检查该持久化对象关联的
集合,对此集合做update/save操作。但是整个操作和外键没有关系。只有当通过多的一方建立关系以后,才能使
外键有值
* 一般一对多设计到关系的维护,都是通过多的一方来操作的
相关文章推荐
- Hibernate 一对一连接表双向关联
- hibernate 多对多双向关联
- Hibernate学习笔记_08_一对一单向、双向主键关联
- Hibernate自身双向一对多关联
- Hibernate双向N-N关联
- Hibernate中关联关系一对多(双向关联)
- Hibernate多对多双向关联(Annotation配置)
- 【Hibernate步步为营】--双向关联一对一映射详解(二)
- hibernate的一对多双向关联映射----客户和订单关系
- Hibernate一对多单向关联和双向关联映射方法及其优缺点
- Hibernate映射——一对一双向关联映射(六)
- Hibernate关系映射(4)_一对一双向主键关联
- 8.4 Hibernate:一对多和多对一双向关联(bidirectional)
- Hibernate多对多双向关联需要注意的问题(实例说话)
- Hibernate一对多单向关联和双向关联映射方法及其优缺点
- 【SSH进阶之路】Hibernate映射——一对一双向关联映射(六)
- Hibernate一对一双向关联映射以及相互引用toString()方法的错误原因
- Hibernate双向一对一外键关联
- Hibernate 一对多外键双向关联
- 【hibernate框架】一对多(多对一)双向关联(XML实现)