上一篇文章中我们将了多对一、一对多的单双边配置,这篇文章我们主要讲一下多对多的单双边配置
Hibernate入门教程 第四章
Hibernate多对多的配置
Hibernate多对多分为2中情况,就是第三张表(中间表)的问题,如果中间表中没有其他的数据是一种,如果第三张表中有其他数据是一种。我们下面将分别对这2中情况进行讲解,我们选择最简单的学生选课为例子。
一、中间表中没有其他字段
1、配置文件
学生类
public class Student200 implements java.io.Serializable {
// Fields
private Integer id;
private String name;
private Set<Course200> courses = new HashSet<Course200>();
// Constructors
/** default constructor */
public Student200() {
}
/** full constructor */
public Student200(String name, Set courses) {
this.name = name;
this.courses = courses;
}
// Property accessors
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Set<Course200> getCourses() {
return courses;
}
public void setCourses(Set<Course200> courses) {
this.courses = courses;
}
}
学生类配置文件 Student200.hbm.xml
<?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.sunny.entity200.Student200" table="student200" catalog="test100">
<id name="id" type="java.lang.Integer">
<column name="student_id" />
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name" length="20" />
</property>
<set name="courses" table="t_student_score">
<key column="student_id"></key>
<many-to-many class="com.sunny.entity200.Course200" column="course_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
班级类
public class Course200 implements java.io.Serializable {
// Fields
private Integer id;
private String name;
private Set<Student200> students = new HashSet<Student200>();
// Constructors
/** default constructor */
public Course200() {
}
/** full constructor */
public Course200(String name) {
this.name = name;
}
// Property accessors
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Set<Student200> getStudents() {
return students;
}
public void setStudents(Set<Student200> students) {
this.students = students;
}
}
班级类配置文件 Course200.hbm.xml
<?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.sunny.entity200.Course200" table="course200" catalog="test100">
<id name="id" type="java.lang.Integer">
<column name="course_id" />
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name" length="20" />
</property>
<set name="students" table="t_student_score">
<key column="course_id"></key>
<many-to-many class="com.sunny.entity200.Student200" column="student_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
我们可以看到配置文件中用的多少many-to-many
2、数据库操作
1、插入数据
//插入数据
public static void fun1(){
Session session = HibernateSessionFactory.getSessionFactory().openSession();
Transaction trans = session.beginTransaction();
Student200 stu = new Student200();
stu.setName("tomcat");
Course200 c1 = new Course200();
c1.setName("c++");
stu.getCourses().add(c1);
Course200 c2 = new Course200();
c2.setName("java");
stu.getCourses().add(c2);
session.save(stu);
session.save(c1);
session.save(c2);
trans.commit();
session.close();
}
2、查询数据
//查询数据
public static void fun2(){
Session session = HibernateSessionFactory.getSessionFactory().openSession();
Query query = session.createQuery("select s,s.name,c.name from Student200 s left join fetch s.courses c");
List<Object[]> list = query.list();
for(Object[] o : list){
System.out.println(o[1]+" "+o[2]);
}
}
这里我们查询的是部分数据,而且我们用的是fetch,上几张中我们将了lazy的用法,我们知道Hibernate中默认lazy为true,既我们开启了延时加载,所以我们要想从学生中抓取课程的信息要fetch。我要说明的是,这句select s,s.name,c.name from Student200 s left join fetch s.courses c 语句中不要fetch效果是一样,left join 和 left join fetch在这里产生的效果是一样的,不知道Hibernate中为什么要可以这2种用法。
3、更新数据
//更行数据
public static void fun3(){
Session session = HibernateSessionFactory.getSessionFactory().openSession();
Transaction trans = session.beginTransaction();
Course200 c = (Course200)session.get(Course200.class, 1);
c.setName("PHP");
session.save(c);
trans.commit();
session.close();
}
4、删除数据
//删除数据
public static void fun4(){
Session session = HibernateSessionFactory.getSessionFactory().openSession();
Transaction trans = session.beginTransaction();
Course200 c = (Course200)session.get(Course200.class, 2);
session.delete(c);
trans.commit();
session.close();
}
二、
中间表中有其他字段
中间表有其他字段在Hibernate中稍微有点不同,我们还以学生选课为例,我们要在第三张表中加入成绩这个字段,上面没有多余字段情况下,我们我们2个类,2个配置文件,如果中间表中有其他的字段,那么我们就必须要产生中间表的类和配置文件,而且在hibernate中,多对多将拆分成2个一对多的情况(当然有其他的配置,我们这里给出常规的配置情况)。
下面我们给出配置方式
1、配置文件
学生类
package com.sunny.entity202;
import java.util.HashSet;
import java.util.Set;
/**
* Student200 entity. @author MyEclipse Persistence Tools
*/
public class Student200 implements java.io.Serializable {
// Fields
private Integer studentId;
private String name;
private Set SCs = new HashSet(0);//SCs对应第三张表选课表
// Constructors
/** default constructor */
public Student200() {
}
/** full constructor */
public Student200(String name, Set SCs) {
this.name = name;
this.SCs = SCs;
}
// Property accessors
public Integer getStudentId() {
return this.studentId;
}
public void setStudentId(Integer studentId) {
this.studentId = studentId;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Set getSCs() {
return this.SCs;
}
public void setSCs(Set SCs) {
this.SCs = SCs;
}
}
学生配置文件
<?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.sunny.entity202.Student200" table="student200" catalog="test100">
<id name="studentId" type="java.lang.Integer">
<column name="student_id" />
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name" length="20" />
</property>
<set name="SCs" inverse="true">
<key>
<column name="student_id" not-null="true" />
</key>
<one-to-many class="com.sunny.entity202.SC" />
</set>
</class>
</hibernate-mapping>
课程类
public class Course200 implements java.io.Serializable {
// Fields
private Integer courseId;
private String name;
private Set SCs = new HashSet(0);
// Constructors
/** default constructor */
public Course200() {
}
/** full constructor */
public Course200(String name, Set SCs) {
this.name = name;
this.SCs = SCs;
}
// Property accessors
public Integer getCourseId() {
return this.courseId;
}
public void setCourseId(Integer courseId) {
this.courseId = courseId;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Set getSCs() {
return this.SCs;
}
public void setSCs(Set SCs) {
this.SCs = SCs;
}
}
课程配置文件
<?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.sunny.entity202.Course200" table="course200" catalog="test100">
<id name="courseId" type="java.lang.Integer">
<column name="course_id" />
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name" length="20" />
</property>
<set name="SCs" inverse="true">
<key>
<column name="course_id" not-null="true" />
</key>
<one-to-many class="com.sunny.entity202.SC" />
</set>
</class>
</hibernate-mapping>
中间表,选课表类
package com.sunny.entity202;
/**
* SC entity. @author MyEclipse Persistence Tools
*/
public class SC implements java.io.Serializable {
// Fields
private Integer id;
private Student200 student200;
private Course200 course200;
private Integer score;
// Constructors
/** default constructor */
public SC() {
}
/** minimal constructor */
public SC(Student200 student200, Course200 course200) {
this.student200 = student200;
this.course200 = course200;
}
/** full constructor */
public SC(Student200 student200, Course200 course200, Integer score) {
this.student200 = student200;
this.course200 = course200;
this.score = score;
}
// Property accessors
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public Student200 getStudent200() {
return this.student200;
}
public void setStudent200(Student200 student200) {
this.student200 = student200;
}
public Course200 getCourse200() {
return this.course200;
}
public void setCourse200(Course200 course200) {
this.course200 = course200;
}
public Integer getScore() {
return this.score;
}
public void setScore(Integer score) {
this.score = score;
}
}
选课类配置文件
<?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.sunny.entity202.SC" table="t_student_score" catalog="test100">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="identity" />
</id>
<many-to-one name="student200" class="com.sunny.entity202.Student200" fetch="select">
<column name="student_id" not-null="true" />
</many-to-one>
<many-to-one name="course200" class="com.sunny.entity202.Course200" fetch="select">
<column name="course_id" not-null="true" />
</many-to-one>
<property name="score" type="java.lang.Integer">
<column name="score" />
</property>
</class>
</hibernate-mapping>
我们从上面配置可以看出,多对多被拆成了2个一对多
2、数据操作
这里我们就给出一个添加的操作,其他的都差不多
//插入数据
public static void fun1(){
Session session = HibernateSessionFactory.getSessionFactory().openSession();
Transaction trans = session.beginTransaction();
Student200 stu = new Student200();
stu.setName("apache");
Course200 c = new Course200();
c.setName("java");
SC sc = new SC();
sc.setCourse200(c);
sc.setStudent200(stu);
sc.setScore(99);
session.save(stu);
session.save(c);
session.save(sc);
trans.commit();
session.close();
}
总结:我在多对多配置有多余字段的情况(多了成绩一个字段)中,我添加了一个主键id,在第一种情况中我没有添加id(选课表中只有2个字段学生id和课程id,联合主键),第二种情况我之所以要添加一个id是因为我如果不添加一个id,那么学生id和课程id就是联合主键,那么就要多出一个类来存储联合主键,看着麻烦,所以我这么做。
在多对多中配置中,像lazy、cascade、fetch、inverse 在前面我都说过,大家可以根据自已情况来选择一下配置,至于单边的配置,只要删除类中和配置文件中相关的地方就可以了,这里不再赘述