一对多双向,从实体类上讲究是在“多”的一端持有“一”的实例,并在配置文件中用<many-to-one>标签将其配置上。这里有一点要特别注意,当两边都能够维护关系的时候,推荐让“多”的一端来做,做法上就是在“一”一端映射文件的<set>标签中设置属性inverse="true"。另外,<key>中为“多”一端表设置的外键要和<many-to-one>中设置的外键要一样。
1.实体模型:
2.关系模型:
3.实体类:
Student.java
public class Student {
private Integer id;
private String name;
private Classes classes;
//一系列的 setter.getter方法
@Override
public String toString() {
return "name of student: " + name;
}
}
private Integer id;
private String name;
private Classes classes;
//一系列的 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>
<!-- 此处column指定的外键要和对方key中指定的外键一致 -->
<many-to-one name="classes" column="class_id" cascade="save-update"></many-to-one>
</class>
<id name="id" length="4">
<generator class="native"></generator>
</id>
<property name="name" length="10"></property>
<!-- 此处column指定的外键要和对方key中指定的外键一致 -->
<many-to-one name="classes" column="class_id" cascade="save-update"></many-to-one>
</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>
<!-- 配置集合属性 -->
<!--inverse="true"含义,把关联关系交由对方一端维护,而在操作本方数据时不再维护关系. -->
<set name="students" cascade="save-update" inverse="true">
<!-- 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>
<!-- 配置集合属性 -->
<!--inverse="true"含义,把关联关系交由对方一端维护,而在操作本方数据时不再维护关系. -->
<set name="students" cascade="save-update" inverse="true">
<!-- 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 {
/**
* 测试插入数据
*/
/* Classes classes = new Classes();//情况1:从"多"的一端保存(这完全就是个多对一的情况)
classes.setName("不一班");
Student student1 = new Student();
student1.setName("志朋");
student1.setClasses(classes);
//存储成功.sql语句如下:
//Hibernate: insert into sxt_hibernate_class (name, id) values (?, ?)
//Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
//Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
//为了不至于出现TransientObjectException,应先保存classes对象或者在<many-to-one>中
//加上cascade="save-update,all"
session.save(student1);
Student student2 = new Student();
student2.setName("有朋");
student2.setClasses(classes);
//由于此时classes已经是持久化对象了,所以此处不会再存储一遍classes了
session.save(student2);
*/
/* Student student1=new Student();//情况2:从"一"的一端保存
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);
//也能正确保存.sql语句如下:
//如果<set>标签中没有inverse="true":(情况2.1)
//Hibernate: insert into sxt_hibernate_class (name, id) values (?, ?)
//Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
//Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
//Hibernate: update sxt_hibernate_student set class_id=? where id=?
//Hibernate: update sxt_hibernate_student set class_id=? where id=?
//存储过程是这样的:存classes时,由于有cascade="save-update",它会先触发存储student,
//由于默认inverse=false,student不负责维护关系,所以此时它的class_id为空;然后回来存储classes,而此时
//classes不得不来维护关系(发出update语句修改student的外键).
//如果<set>标签中有inverse="true":(情况2.2)
//Hibernate: insert into sxt_hibernate_class (name, id) values (?, ?)
//Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
//Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
//但是插入的student记录class_id字段为空,因为"一"一端不再负责维护关系了.
//存储过程是这样的:存classes时,由于有cascade="save-update",它会先触发存储student;
// 而在存储student时,虽然inverse="true"指明了由它来维护关联关系,所以他要先存主表class,
// 再回来存副表student,但是student发现它的classes为null,就把class_id字段设为了空.
session.save(classes);
*/
/* Classes classes=new Classes();//情况3
classes.setName("不一班");
Student student1=new Student();
student1.setName("志鹏");
student1.setClasses(classes);
Student student2=new Student();
student2.setName("有朋");
student2.setClasses(classes);
Set<Student> students=new HashSet<Student>();
students.add(student1);
students.add(student2);
classes.setStudents(students);
//同样能正确保存.sql语句如下:
//如果<set>标签中有inverse="true",cascade="save-update":
//Hibernate: insert into sxt_hibernate_class (name, id) values (?, ?)
//Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
//Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
//这种情况student的class_id也有了,因为在插入student时,由student来维护了关系,而它引用的class已经是持久化的了.
//存储过程是这样的:存classes时,由于有cascade="save-update",它会先触发存储student;
// 而在存储student时,inverse="true"指明了由它来维护关联关系,所以他要先存主表class,再回来存副表student
session.save(classes);*/
/**
* 小结:情况1是我们提倡的;
* 情况2.1虽然也能实现正确插入,但是效率低;
* 情况2.2显然是错误的;
* 情况3虽然也能实现,并且效率也不低,但是编程上比较麻烦.
*/
/**
* 测试加载数据
*/
Student student=(Student)session.get(Student.class, 3);
System.out.println(student);
System.out.println(student.getClasses());
t.commit();
} catch (HibernateException e) {
e.printStackTrace();
t.rollback();
} finally {
HibernateUtils.closeSession(session);
}
}
}
Session session = HibernateUtils.getSession();
Transaction t = session.beginTransaction();
try {
/**
* 测试插入数据
*/
/* Classes classes = new Classes();//情况1:从"多"的一端保存(这完全就是个多对一的情况)
classes.setName("不一班");
Student student1 = new Student();
student1.setName("志朋");
student1.setClasses(classes);
//存储成功.sql语句如下:
//Hibernate: insert into sxt_hibernate_class (name, id) values (?, ?)
//Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
//Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
//为了不至于出现TransientObjectException,应先保存classes对象或者在<many-to-one>中
//加上cascade="save-update,all"
session.save(student1);
Student student2 = new Student();
student2.setName("有朋");
student2.setClasses(classes);
//由于此时classes已经是持久化对象了,所以此处不会再存储一遍classes了
session.save(student2);
*/
/* Student student1=new Student();//情况2:从"一"的一端保存
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);
//也能正确保存.sql语句如下:
//如果<set>标签中没有inverse="true":(情况2.1)
//Hibernate: insert into sxt_hibernate_class (name, id) values (?, ?)
//Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
//Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
//Hibernate: update sxt_hibernate_student set class_id=? where id=?
//Hibernate: update sxt_hibernate_student set class_id=? where id=?
//存储过程是这样的:存classes时,由于有cascade="save-update",它会先触发存储student,
//由于默认inverse=false,student不负责维护关系,所以此时它的class_id为空;然后回来存储classes,而此时
//classes不得不来维护关系(发出update语句修改student的外键).
//如果<set>标签中有inverse="true":(情况2.2)
//Hibernate: insert into sxt_hibernate_class (name, id) values (?, ?)
//Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
//Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
//但是插入的student记录class_id字段为空,因为"一"一端不再负责维护关系了.
//存储过程是这样的:存classes时,由于有cascade="save-update",它会先触发存储student;
// 而在存储student时,虽然inverse="true"指明了由它来维护关联关系,所以他要先存主表class,
// 再回来存副表student,但是student发现它的classes为null,就把class_id字段设为了空.
session.save(classes);
*/
/* Classes classes=new Classes();//情况3
classes.setName("不一班");
Student student1=new Student();
student1.setName("志鹏");
student1.setClasses(classes);
Student student2=new Student();
student2.setName("有朋");
student2.setClasses(classes);
Set<Student> students=new HashSet<Student>();
students.add(student1);
students.add(student2);
classes.setStudents(students);
//同样能正确保存.sql语句如下:
//如果<set>标签中有inverse="true",cascade="save-update":
//Hibernate: insert into sxt_hibernate_class (name, id) values (?, ?)
//Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
//Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)
//这种情况student的class_id也有了,因为在插入student时,由student来维护了关系,而它引用的class已经是持久化的了.
//存储过程是这样的:存classes时,由于有cascade="save-update",它会先触发存储student;
// 而在存储student时,inverse="true"指明了由它来维护关联关系,所以他要先存主表class,再回来存副表student
session.save(classes);*/
/**
* 小结:情况1是我们提倡的;
* 情况2.1虽然也能实现正确插入,但是效率低;
* 情况2.2显然是错误的;
* 情况3虽然也能实现,并且效率也不低,但是编程上比较麻烦.
*/
/**
* 测试加载数据
*/
Student student=(Student)session.get(Student.class, 3);
System.out.println(student);
System.out.println(student.getClasses());
t.commit();
} catch (HibernateException e) {
e.printStackTrace();
t.rollback();
} finally {
HibernateUtils.closeSession(session);
}
}
}
本文出自 “夜狼” 博客,请务必保留此出处http://yangfei520.blog.51cto.com/1041581/275947
相关推荐
本篇文章将详细探讨双向一对一主键关联映射的概念、配置以及实际应用。 首先,我们需要了解一对一关联的类型。一对一关联分为两种:基于主键的关联(Primary Key Association)和基于外键的关联(Foreign Key ...
本主题聚焦于“Hibernate双向一对一关联映射”的注解实现,这是一种高级的数据库设计模式,用于处理两个实体之间一对一的关系。 在Hibernate中,一对一关联映射分为单向和双向。单向一对一映射通常涉及一个实体持有...
在Java的持久化框架Hibernate中,一对多关联映射是一种常见的关系映射方式,它用于表示一个实体(如用户)可以拥有多个子实体(如订单)的情况。在本篇文章中,我们将深入探讨如何实现双向关联的一对多映射,以及在...
##### 双向一对多关联映射 双向映射中,双方都会维护关联关系。例如,除了班级类维护一个学生列表外,每个学生还持有所属班级的引用。 ```java public class Class { private int id; private String name; @...
在Java的持久化框架Hibernate中,双向一对多关联映射是一种常见的关系映射方式,它模拟了数据库中的外键关联,使得一个实体可以拥有多个另一个实体的实例。在这个注解版的实现中,我们将深入探讨如何使用Hibernate的...
在Java的持久化框架Hibernate中,双向多对多关联映射是一种常见的数据关系模型,它允许两个实体类之间存在多个实例互相引用的情况。本练习旨在帮助开发者深入理解并熟练运用这种映射方式。通过以下详细讲解,我们将...
在Java的持久化框架Hibernate中,双向一对多关联映射是一种常见的关系数据库模型与对象模型之间的映射方式。这种映射允许在一个实体类中存在多个另一个实体类的实例,而在另一个实体类中也可能存在对第一个实体类的...
包含《多对多双向关联映射》《多对一单向关联映射》《多对一双向关联映射》《一对多单向关联映射》等文档,并有图解及例子,非常适合新手学习,尤其是刚刚接触hibernate,对映射关系不清楚的。。。。
本文将深入探讨Hibernate中的一对多关联映射,以及如何实现双向关联。 一、Hibernate一对多关联映射 1.1 单向关联:在单向一对多关联中,一个实体类知道另一个实体类,而另一个实体类并不知情。这通常通过在一方...
在Java的持久化框架Hibernate中,多对多关联映射是一种常见的关系模型,它用于处理两个实体类之间存在多个对应关系的情况。这篇博客"hibernate多对多关联映射(单项关联)"深入探讨了如何在Hibernate中实现这种映射...
在一对多关联映射中,还有单向关联和双向关联之分。单向关联是指一端维护多端的关系,而多端不知道一端的存在。双向关联是指一端维护多端的关系,而多端也维护一端的关系。 在本文中,我们通过一个简单的示例来演示...
在数据库设计中,一对多关联是指一个实体可以与多个其他实体相关联,比如一个学生可以有多个课程,一个部门可以有多名员工。在Hibernate中,这种关系可以通过XML映射文件来配置。首先,我们需要在两个实体的映射文件...
在这个“hibernate双向多对多关联映射(注解版)”的主题中,我们将深入探讨如何使用Hibernate的注解配置来处理数据库中的双向多对多关联关系。 首先,多对多关联在数据库设计中是指两个实体之间存在多个对应关系,...
**一对多关联** 在数据库设计中,一对多关系意味着一个表的记录可以与另一个表的多个记录相关联。在Hibernate中,这种关系可以通过`@OneToMany`注解实现。例如,User类可能会有如下注解: ```java @Entity public ...
本知识点将深入探讨Hibernate中的双向多对多关联映射,并通过XML配置文件进行设置。 在关系型数据库中,多对多(Many-to-Many)关系是两个表之间的一种复杂关联,表示一个实体可以与多个其他实体相关联,反之亦然。...
2. 创建双向一对多关联,如“街道”和“区县”的双向关系。 3. 实现多对多关联,例如OA系统中项目和人员的对应关系管理。 在实体类中,我们可以使用注解或XML映射文件来定义关联。例如,在上述的“区县”和“街道”...
接着是双向一对多关联映射(BidirectionalOneToMany)。在这种关系中,一个实体可以拥有多个其他实体,而其他实体只能有一个父实体。例如,一个用户可以有多个订单,但每个订单只属于一个用户。双向关联意味着在用户...
在MyBatis中,实现一对多关联有两种方式:集合映射和关联映射。集合映射通常用于一个实体包含一个列表或集合的子实体,而关联映射则允许更复杂的导航结构。在这个系列的第三部分,我们将重点讨论双向关联,这意味着...
本主题将主要聚焦在一对一和一对多关联。 2. **关联的方向性:** 关联可以是单向或双向的。单向关联只能从一个实体访问另一个,而双向关联允许两个实体之间互相访问。 3. **@OneToOne, @OneToMany, @ManyToOne ...