ITEEDU

Hibernate-one-to-many映射

one-to-many

one-to-many是一对多映射,如班级和学生的关系。

一对多也分为单向和双向之分。

一对多单向

学生类

package com.iteedu.hibernate;

public class Student {

	private int id;

	private String name;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

 学生类映射文件

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class name="com.iteedu.hibernate.Student" table="t_student">
		<id name="id">
			<generator class="native"/>
		</id>
		<property name="name"/>
	</class>
</hibernate-mapping>

 班级类

package com.iteedu.hibernate;

import java.util.Set;

public class Classes {

	private int id;

	private String name;

	private Set students; 

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Set getStudents() {
		return students;
	}

	public void setStudents(Set students) {
		this.students = students;
	}
}

这里的一对多用集合Set来实现。

班级类映射文件

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.iteedu.hibernate">
	<class name="Classes" table="t_classes">
		<id name="id">
			<generator class="native"/>
		</id>
		<property name="name"/>
		<set name="students">
			<key column="classesid"/>
			<one-to-many class="Student"/>
		</set>
	</class>
</hibernate-mapping>

这里主要说一下set的配制。

<one-to-many/>

这是确定Set中是什么对象,也通过class找到类和对应映射文件,就可以找到数据库中的表了。

<key column="classesid"/>

找到表怎么做关联,这就要一个外键来指定,key就是指定外键的列名的,是数据库中的列的名称。

调用

保存

session.beginTransaction();

Student student1 = new Student();
student1.setName("QQ");
session.save(student1);

Student student2 = new Student();
student2.setName("360");
session.save(student2);

Set students = new HashSet();
students.add(student1);
students.add(student2);

Classes classes = new Classes();
classes.setName("ITEEDU");
classes.setStudents(students);

//可以正确保存
session.save(classes);
session.getTransaction().commit();

加载

session.beginTransaction();

Classes classes = (Classes)session.load(Classes.class, 1);
System.out.println("classes.name=" + classes.getName());
Set students = classes.getStudents();
for (Iterator iter=students.iterator(); iter.hasNext();) {
    Student student = (Student)iter.next();
    System.out.println("student.name=" + student.getName());
}
session.getTransaction().commit();

 

一对多双向

一对多双向,一的一方不变,多的一方加上many-to-one配制。

学生类添加属性

private Classes classes;
public Classes getClasses() {
    return classes;
}
public void setClasses(Classes classes) {
    this.classes = classes;
}

 映射文件添加属性

<many-to-one name="classes" column="classesid"/>

其中column要和一的一端Set中的key相同。其实就是数据库要用同一个列关联。

调用

保存

session.beginTransaction();

Classes classes = new Classes();
classes.setName("ITEEDU");
session.save(classes);

Student student1 = new Student();
student1.setName("QQ");
student1.setClasses(classes);
session.save(student1);

Student student2 = new Student();
student2.setName("360");
student2.setClasses(classes);
session.save(student2);

session.getTransaction().commit();

加载

session.beginTransaction();

Student student = (Student)session.load(Student.class, 1);
System.out.println("student.name=" + student.getName());
System.out.println("student.classes.name=" + student.getClasses().getName());
session.getTransaction().commit();

 

缺点和解决

在一的一端维护关系的缺点:

如果将t_student表里的classesid字段设置为非空,则无法保存。

因为不是在student这一端维护关系,所以student不知道是哪个班的,所以需要发出多余的update语句来更新关系。

解决方法:

如果在一的一端维护一对多关联关系,hibernate会发出多余的udpate语句,所以我们一般在多的一端来维护关联关系。

关系反转inverse和级联cascade。

  1. inverse是关联关系的控制方向
  2. cascade操作上的连锁反应

inverse主要用在一对多和多对多双向关联上,inverse可以被设置到集合标签<set>上,默认inverse为false,所以我们可以从一的一端和多的一端维护关联关系,如果设置成inverse为true,则我们只能从多的一端来维护关联关系。

<set name="students" inverse="true" cascade="all">
		<key column="classesid"/>
		<one-to-many class="Student"/>
</set>

保存示例:

session.beginTransaction();

Classes classes = new Classes();
classes.setName("ITEEDU");

Student student1 = new Student();
student1.setName("QQ");
student1.setClasses(classes);

Student student2 = new Student();
student2.setName("360");
student2.setClasses(classes);

Set students = new HashSet();
students.add(student1);
students.add(student2);
classes.setStudents(students);

session.save(classes);
session.getTransaction().commit();

在保存classes时,由于双向关联,学生设置了班级,所以先保存班级,再保存学生(级联后自动保存学生)。