上篇文章讨论了双向关联的一对一映射,用了两个章节,主要是从主键和外键两种关联映射展开具体讨论。双向关联的映射须要在两个映射文件里分别加入相互的相应关系。斌刚在相应的类中加入相应的关联类的属性。这样在一端载入时才干载入到还有一端的对象。关联中经常使用的主要有多对一、一对一、一对多和多对多。我们已经讨论了两种映射关系。接下来将会讨论一对多的关系。


一、单向一对多

        前篇文章中以前对多对一的关系展开了讨论,当中主要使用的是<many-to-one>的关系,在多的一端维护一的一端,那和今天要讨论的一对多的关系它们之间是否有关联呢?在关系和对象模型中存在了一对多关系所以理所当然就会有多对一的关系,Hibernate相同提供了一对多关系的标签<one-to-many>。

        一对多关系的对象模型在日常生活中也常常看到,就拿学生和班级来说。一个班级里有多个学生。所以班级和学生的关系是一对多的关系,映射到对象模型中。例如以下图:
【Hibernate步步为营】--(一对多映射)之单向关联_映射文件
       对象模型说明了这样的一对多的关系是由一的一端来维护的,那么映射成关系模型就是一个班级字段以下会有多个学生,这样就形成了一对多的关系,通过班级可以查询获得学生信息,相应的关系模型例如以下图:
【Hibernate步步为营】--(一对多映射)之单向关联_映射文件_02

  1、基本配置


       有了对象模型接下来就让它们映射为相应的关系代码。在进行关系映射时须要在一的一端加入<one-to-many>标签。另外还须要在一的一端加入Set属性,它支持延迟载入,然后在映射文件加入set标签。并指明一对多的关系,这样就行在一的一端查询获取多的一端。

    Classes类及映射文件
      它是模型中最重要的一端,在该端须要加入相应的set属性。并在配置文件里加入set标签,在set标签中配置相应的<one-to-many>对象,详细Classes.java对象代码例如以下:
<pre name="code" class="java">package com.src.hibernate;

import java.util.Set;

public class Classes {
	private int id;
	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;
	}
	private String name;
	
	//Set支持延迟载入
	private Set students;
	public Set getStudents() {
		return students;
	}
	public void setStudents(Set students) {
		this.students = students;
	}
}

      Classes对象中使用了set属性。可是仅仅是说明了延迟载入的属性,并没有为属性配置相应的对象。属性的对象是要在映射文件里来配置的。须要加入set标签,并在set标签中加入<one-to-many>标签,详细例如以下代码:
<?

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.hibernate.Classes" table="t_classes"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <set name="students"> <key column="classesid"></key> <one-to-many class="com.hibernate.Student"></one-to-many> </set> </class> </hibernate-mapping>


        相应的Student对象中的代码和映射文件不须要什么特殊的配置,仅仅须要依照通常的写法编写就可以,详细的配置方法不再详述,非常easy。

配置好后须要生成相应的SQL语句。将对象模型转化为关系模型时Hibernate生成相应的语句例如以下:

alter table t_student drop foreign key FK4B9075705E0AFEFE
drop table if exists t_classes
drop table if exists t_student
create table t_classes (id integer not null auto_increment, name varchar(255), primary key (id))
create table t_student (id integer not null auto_increment, name varchar(255), classesid integer, primary key (id))
alter table t_student add index FK4B9075705E0AFEFE (classesid), add constraint FK4B9075705E0AFEFE foreign key (classesid) references t_classes (id)

      生成的相应的关系模型例如以下图:
【Hibernate步步为营】--(一对多映射)之单向关联_关系模型_03
 对照SQL语句和关系模型。对应的表之间的关联是通过外键来维护的,首先是创建两张表,并指定表的主键,最后加入一对多的外键关联关系。

  2、基本操作

       在对数据库的操作无非是读和写两种。改动也属于写的一种,接下来看看是怎样向数据库中写入和读取操作的。

       写入数据
       写入数据须要注意的是一对多的关系,所以在加入的时候须要加入多个学生类,另外因为在classes中加入了相应的set属性,所以在加入Student对象时应该使用HashSet来加入,这样既可实现一对多的关系,详细例如以下代码:
public void testSave2(){
	Session session=null;
	try{
		session=HibernateUtils.getSession();
		session.beginTransaction();
		
		Student student1=new Student();
		student1.setName("zhangsan");
		session.save(student1);
		
		Student student2=new Student();
		student2.setName("lisi");
		session.save(student2);
		
		Classes classes=new Classes();
		classes.setName("ClassOne");
		
		Set students=new HashSet();
		students.add(student1);
		students.add(student2);
		
		classes.setStudents(students);
		//能够成功保存数据
		//可是会发出多余的update语句来维持关系,由于是一对多的原因
		session.save(classes);
		session.getTransaction().commit();
	}catch(Exception e){
		e.printStackTrace();
		session.getTransaction().rollback();
	}finally{
		HibernateUtils.closeSession(session);
	}
}

        那么执行上面的測试用例生成的相应的数据写入到数据库中后例如以下图:
【Hibernate步步为营】--(一对多映射)之单向关联_hibernate_04

       读取数据
       写入操作相对简单,仅仅须要把全部载入的对象都加入到Transient状态下。执行相应的方法就能够插入内容。可是相应的读取操作就会略微复杂点,由于须要迭代获取全部的学生对象,所以这样的一对多的关系效率并不非常高。详细代码例如以下:
package com.test.hibernate;

import java.util.Iterator;
import java.util.Set;
import com.src.hibernate.*;
import junit.framework.TestCase;
import org.hibernate.Session;

public class One2ManyTest extends TestCase {
	public void testLoad1(){
		Session session=null;
		try{
			session=HibernateUtils.getSession();
			session.beginTransaction();
			
			//获取主键为5的班级信息
			Classes classes=(Classes)session.load(Classes.class,5);
			//打印班级信息
			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();
		}catch(Exception e){
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally{
			HibernateUtils.closeSession(session);
		}
	}
}

      生成的对应的语句及信息例如以下语句:
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=?

classes.name=ClassOne Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id0_0_, students0_.name as name0_0_ from t_student students0_ where students0_.classesid=?

student.name=lisi student.name=zhangsan


结语

        一对多的关系也是经经常使用到的,可是这样的关系在载入时效率会不高。由于须要维护的数据较多,所以不建议使用一对多的关系,能够考虑多对一的关系。这样在载入时事实上是一种一对一的关系,载入的效率较高,关系和对象模型得到了优化。这里仅仅是讨论了单向的一对多,下篇文章讨论双向的关联关系。