Hibernate从入门到精通(5)- 双向 一对多

来源:互联网 发布:淘宝上有卖岛国片cd 编辑:程序博客网 时间:2024/04/29 11:41

Hibernate双向一对多

还是使用班级-学生进行测试:
双向:更新一张表,另一张表中与之相关联的数据都进行更新,两张表都可以相互查询。
单向:主表更新,从表更新。从表更新,主表不管。主表可以查询到从表内容,从表不能查询主表内容。

映射

ClassInfo实体类:
package com.edu.entity;import java.io.Serializable;import java.util.HashSet;import java.util.Set;public class ClassInfo implements Serializable{private static final long serialVersionUID = 1L;private Integer claId;private String claName;private Set<Student> stus = new HashSet<>();<span style="white-space:pre"></span>//getter setter}

ClassInfo.hbm.xml:
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><!-- Generated 2015-11-1 14:31:20 by Hibernate Tools 3.4.0.CR1 --><hibernate-mapping>    <class name="com.edu.entity.ClassInfo" table="CLASS_INFO">        <id name="claId" type="java.lang.Integer" access="field">            <column name="CLA_ID" />            <generator class="assigned" />        </id>        <property name="claName" type="java.lang.String" access="field">            <column name="CLA_NAME" />        </property>        <!-- inverse为true 关系由对方维持 -->        <set name="stus" table="STUDENT" inverse="true" lazy="true" access="field"        cascade="save-update">            <key>            <!-- 多的一方的外键名 -->                <column name="CLA_ID" />            </key>            <one-to-many class="com.edu.entity.Student" />        </set>    </class></hibernate-mapping>

Student实体类:
package com.edu.entity;import java.io.Serializable;public class Student implements Serializable {private static final long serialVersionUID = 1L;private Integer stuId;private String stuName;private ClassInfo classInfo;//getter setter}

student.hbm.xml:
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><!-- Generated 2015-11-1 14:31:20 by Hibernate Tools 3.4.0.CR1 --><hibernate-mapping>    <class name="com.edu.entity.Student" table="STUDENT">        <id name="stuId" type="java.lang.Integer" access="field">            <column name="STU_ID" />            <generator class="assigned" />        </id>        <property name="stuName" type="java.lang.String" access="field">            <column name="STU_NAME" />        </property>        <!-- many-to-one 无inverse属性 默认为false -->        <many-to-one name="classInfo" class="com.edu.entity.ClassInfo"         access="field" fetch="join" cascade="save-update" >            <column name="CLA_ID" />        </many-to-one>    </class></hibernate-mapping>

测试类:
package com.edu.util;import org.hibernate.Session;import org.hibernate.Transaction;import org.junit.After;import org.junit.Before;import org.junit.Test;import com.edu.entity.ClassInfo;import com.edu.entity.Student;public class HibernateUtilsTest {private Session session = null;private Transaction tran = null;@Beforepublic void initSession(){session = HibernateUtils.getSession();tran = session.beginTransaction();}public void testGet(){//ClassInfo classInfo = (ClassInfo) session.get(ClassInfo.class, 10);//System.out.println(classInfo.toString());Student stu = (Student) session.get(Student.class, 2);System.out.println(stu.toString());}/** * 通过班级添加学生 */@Testpublic void testSave1(){Student stu1 = new Student();stu1.setStuId(1);stu1.setStuName("学生1");Student stu2 = new Student();stu2.setStuId(2);stu2.setStuName("学生2");ClassInfo classInfo = new ClassInfo();classInfo.setClaId(10);classInfo.setClaName("十班");classInfo.getStus().add(stu1);classInfo.getStus().add(stu2);//当inverse=true的时候,这里应该添加!不然数据库中外键没有数据stu2.setClassInfo(classInfo);session.save(classInfo);}/** * 通过学生添加班级 */public void testSave2(){Student stu1 = new Student();stu1.setStuId(1);stu1.setStuName("学生1");ClassInfo classInfo = new ClassInfo();classInfo.setClaId(10);classInfo.setClaName("十班");stu1.setClassInfo(classInfo);;session.save(stu1);}@Afterpublic void colseSession(){if(tran!=null){tran.commit();}if(session!=null&&session.isOpen()){session.close();}}}
*注:这里要注意班级和学生之间的关系由谁来负责维护,使用映射文件进行配置中,many-to-one中没有inverse这个属性,或者可以认为默认为true,如果在one-to-many中inverse=false,那么他们两个之间的关系就由班级来负责,每次添加班级信息,都会重新update学生信息,如图:

这样是极为繁琐的,就和老板和员工之间,是让老板一个个去认识员工方便,还是所有员工都认识老板方便?很明显,在学生和班级之间,让学生负责维护他们之间的关系更好,或者说多的一方维护。当学生维护的时候,即inverse=true的时候,注意给学生添加一个班级,否则会出现:
数据库中:

这里的学生外键并没有数据,在inverse=true的时候,添加stu.setClassInfo(classInfo);

注解Annotation

ClassInfo实体类:
package com.edu.entity;import java.io.Serializable;import java.util.HashSet;import java.util.Set;import javax.persistence.CascadeType;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.FetchType;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.OneToMany;import javax.persistence.SequenceGenerator;import javax.persistence.Table;@Entity@Table(name="class_info")public class ClassInfo implements Serializable{private static final long serialVersionUID = 1L;@Id@SequenceGenerator(name="seq_gener_class",allocationSize=5,sequenceName="seq_class_info_id")@GeneratedValue(generator="seq_gener_class",strategy=GenerationType.SEQUENCE)@Column(name="cla_id")private Integer claId;@Column(name="cla_name")private String claName;//mappedBy和映射文件中的inverse相同,值为多的一方的映射属性名(inverse=true)@OneToMany(targetEntity=Student.class,cascade=CascadeType.ALL,mappedBy="classInfo",fetch=FetchType.LAZY)private Set<Student> stus = new HashSet<>();//getter setter}

Student实体类:
package com.edu.entity;import java.io.Serializable;import javax.persistence.CascadeType;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.JoinColumn;import javax.persistence.ManyToOne;import javax.persistence.SequenceGenerator;import javax.persistence.Table;@Entity@Table(name="student")public class Student implements Serializable {private static final long serialVersionUID = 1L;@Id@SequenceGenerator(name="seq_gener_stu",allocationSize=5,sequenceName="seq_student_id")@GeneratedValue(generator="seq_gener_stu",strategy=GenerationType.SEQUENCE)@Column(name="stu_id")private Integer stuId;@Column(name="stu_name")private String stuName;@ManyToOne(targetEntity=ClassInfo.class,cascade=CascadeType.ALL)@JoinColumn(name="cla_id")private ClassInfo classInfo;<span style="white-space:pre"></span>//getter setter}

测试类:
package com.edu.util;import org.hibernate.Session;import org.hibernate.Transaction;import org.junit.After;import org.junit.Before;import org.junit.Test;import com.edu.entity.ClassInfo;import com.edu.entity.Student;public class HibernateUtilsTest {private Session session = null;private Transaction tran = null;@Beforepublic void initSession(){session = HibernateUtils.getSession();tran = session.beginTransaction();}public void testGet(){//ClassInfo classInfo = (ClassInfo) session.get(ClassInfo.class, 10);//System.out.println(classInfo.toString());//Student stu = (Student) session.get(Student.class, 2);//System.out.println(stu.toString());}public void testSave1(){Student stu1 = new Student();stu1.setStuName("学生1");Student stu2 = new Student();stu2.setStuName("学生2");ClassInfo classInfo = new ClassInfo();classInfo.setClaName("十班");//ClassInfo classInfo2 = new ClassInfo();//classInfo2.setClaId(20);//classInfo2.setClaName("2班");classInfo.getStus().add(stu1);classInfo.getStus().add(stu2);stu1.setClassInfo(classInfo);stu2.setClassInfo(classInfo);session.save(classInfo);}@Testpublic void testSave2(){Student stu1 = new Student();stu1.setStuName("学生1");ClassInfo classInfo = new ClassInfo();classInfo.setClaName("十班");stu1.setClassInfo(classInfo);;session.save(stu1);}@Afterpublic void colseSession(){if(tran!=null){tran.commit();}if(session!=null&&session.isOpen()){session.close();}}}
注解基本和映射文件相同,只有一点,当学生和班级之间的关系由学生负责维护的时候,使用的是mappBy代替的inverse。如:在one-to-many中添加mappBy,其值为多的一方的映射属性名,即:Student中的Teacher对象名。

总结:
inverse指的是两个对象之间的关系由谁负责维持。
     fetch是值查询的时候以什么样的形式查询,内查询,子查询,外查询或者以什么方式查询,是否查询相关联的数据。
    cascade为级联,在可以操作对方的前提下,进行同步的CRUD。

1 0
原创粉丝点击