“一对多”,顾名思义,是由“一”的一端加载“多”的一端,关系交由“一”来维护。反映在Java代码中就是在“一”的一端中持有“多”一端的集合,而hibernate把这种关系反映到数据库的策略是在“多”一端的表上加上一个外键指向“一”一端表。显现,其实这采用的还是“多対一”的映射原理。
但是,在“一”一端维护关系是我们不提倡的,因为它有不可避免的缺点,即级联插入数据的时候要先插“多”一端,这样造成了两方面的不妥:1.如果我们把“多”一端的外键必须添加非空约束,将导致数据不能插入;2.即使外键不设置为非空,在插入“多”一端数据时外键将暂时为空( 因为此时它所引用的“一”记录还没有插入),而只有等到它所引用的“一”记录插入后,再发出update语句修改外键,这样的效率必然降低。
不管怎样,还是来看看我的Classes和Student怎么做的吧。
1.实体模型:
2.关系模型:
3.实体类:
Student.java
public
class Student {
private Integer id;
private String name;
//一系列的setter.getter方法
@Override
public String toString() {
return "name of student: " + name;
}
}
private Integer id;
private String name;
//一系列的setter.getter方法
@Override
public String toString() {
return "name of student: " + name;
}
}
Classes.java
public
class Classes {
private Integer id;
private String name;
private Set<Student> students;
//一系列的setter.getter方法
@Override
public String toString() {
return "name of class: " + name;
}
}
private Integer id;
private String name;
private Set<Student> students;
//一系列的setter.getter方法
@Override
public String toString() {
return "name of class: " + name;
}
}
4.映射文件:
Student.hbm.xml
<
class
name
="com.sxt.hibernate.one2many.entity.Student"
table
="sxt_hibernate_student"
>
< id name ="id" length ="4" >
< generator class ="native" > </ generator >
</ id >
< property name ="name" length ="10" > </ property >
</ class >
< id name ="id" length ="4" >
< generator class ="native" > </ generator >
</ id >
< property name ="name" length ="10" > </ property >
</ class >
Classes.hbm.xml
<
class
name
="com.sxt.hibernate.one2many.entity.Classes"
table
="sxt_hibernate_class"
>
< id name ="id" length ="4" >
< generator class ="native" > </ generator >
</ id >
< property name ="name" length ="10" > </ property >
<!-- 配置集合属性 -->
< set name ="students" cascade ="save-update" >
<!-- key的含义,指在另一端增加的外键指向本主键.
如果设置上属性not-null="true",表示该外键非空,则在由"一"的一端维护关系时,
可能导致插入数据异常PropertyValueException.
-->
< key column ="class_id" > </ key >
<!-- one-to-many含义,指出set集合中的元素类型,以供加载时使用 -->
< one-to-many class ="com.sxt.hibernate.one2many.entity.Student" />
</ set >
</ class >
< id name ="id" length ="4" >
< generator class ="native" > </ generator >
</ id >
< property name ="name" length ="10" > </ property >
<!-- 配置集合属性 -->
< set name ="students" cascade ="save-update" >
<!-- key的含义,指在另一端增加的外键指向本主键.
如果设置上属性not-null="true",表示该外键非空,则在由"一"的一端维护关系时,
可能导致插入数据异常PropertyValueException.
-->
< key column ="class_id" > </ key >
<!-- one-to-many含义,指出set集合中的元素类型,以供加载时使用 -->
< one-to-many class ="com.sxt.hibernate.one2many.entity.Student" />
</ set >
</ class >
5.hibernate配置文件:
参考前面的。
6.测试方法:
public
static
void main(String[] args) {
Session session = HibernateUtils.getSession();
Transaction t = session.beginTransaction();
try {
/**
* 测试插入数据
*/
/*
* Student student1=new Student();
* student1.setName("奇隆");
*
* Student student2=new Student();
* student2.setName("有朋");
*
* Set<Student> students=new HashSet<Student>();
* students.add(student1);
* students.add(student2);
*
* Classes classes=new Classes();
* classes.setName("不一班");
* classes.setStudents(students);
* //存储不成功.报错:org.hibernate.TransientObjectException
* //因为此时student对象还没有持久化,classes引用了瞬时对象student1,student2
* session.save(classes);
*/
Student student1= new Student(); student1.setName( "奇隆");
//session.save(student1);//先把student对象持久化
Student student2= new Student();
student2.setName( "有朋");
//session.save(student2);
Set<Student> students= new HashSet<Student>();
students.add(student1);
students.add(student2);
Classes classes= new Classes();
classes.setName( "不一班");
classes.setStudents(students);
//存储成功.sql语句如下:
/*
Hibernate: insert into sxt_hibernate_class (name, id) values (?, ?)
Hibernate: insert into sxt_hibernate_student (name, id) values (?, ?)
Hibernate: insert into sxt_hibernate_student (name, id) values (?, ?)
Hibernate: update sxt_hibernate_student set class_id=? where id=?
Hibernate: update sxt_hibernate_student set class_id=? where id=? */
//可见在存储class之后,发出两个update语句,把它的两个student对象的class_id更新了.
//这是因为关系由"一"的一端维护(即class维护关系).这显然会降低效率.
//所以对于一对多,我们一般把关系交给"多"的一端维护.
session.save(classes);
/**
* 测试加载数据
*/
/* Classes classes = (Classes) session.load(Classes.class, 3);
System.out.println(classes);
Set<Student> students = classes.getStudents();
for (Iterator<Student> stus = students.iterator(); stus.hasNext();) {
System.out.println(stus.next());
}*/
t.commit();
} catch (HibernateException e) {
e.printStackTrace();
t.rollback();
} finally {
HibernateUtils.closeSession(session);
}
}
}
Session session = HibernateUtils.getSession();
Transaction t = session.beginTransaction();
try {
/**
* 测试插入数据
*/
/*
* Student student1=new Student();
* student1.setName("奇隆");
*
* Student student2=new Student();
* student2.setName("有朋");
*
* Set<Student> students=new HashSet<Student>();
* students.add(student1);
* students.add(student2);
*
* Classes classes=new Classes();
* classes.setName("不一班");
* classes.setStudents(students);
* //存储不成功.报错:org.hibernate.TransientObjectException
* //因为此时student对象还没有持久化,classes引用了瞬时对象student1,student2
* session.save(classes);
*/
Student student1= new Student(); student1.setName( "奇隆");
//session.save(student1);//先把student对象持久化
Student student2= new Student();
student2.setName( "有朋");
//session.save(student2);
Set<Student> students= new HashSet<Student>();
students.add(student1);
students.add(student2);
Classes classes= new Classes();
classes.setName( "不一班");
classes.setStudents(students);
//存储成功.sql语句如下:
/*
Hibernate: insert into sxt_hibernate_class (name, id) values (?, ?)
Hibernate: insert into sxt_hibernate_student (name, id) values (?, ?)
Hibernate: insert into sxt_hibernate_student (name, id) values (?, ?)
Hibernate: update sxt_hibernate_student set class_id=? where id=?
Hibernate: update sxt_hibernate_student set class_id=? where id=? */
//可见在存储class之后,发出两个update语句,把它的两个student对象的class_id更新了.
//这是因为关系由"一"的一端维护(即class维护关系).这显然会降低效率.
//所以对于一对多,我们一般把关系交给"多"的一端维护.
session.save(classes);
/**
* 测试加载数据
*/
/* Classes classes = (Classes) session.load(Classes.class, 3);
System.out.println(classes);
Set<Student> students = classes.getStudents();
for (Iterator<Student> stus = students.iterator(); stus.hasNext();) {
System.out.println(stus.next());
}*/
t.commit();
} catch (HibernateException e) {
e.printStackTrace();
t.rollback();
} finally {
HibernateUtils.closeSession(session);
}
}
}
本文转自NightWolves 51CTO博客,原文链接:
http://blog.51cto.com/yangfei520/275656
,如需转载请自行联系原作者