【Hibernate步步为营】--(一对多映射)之双向关联
上篇文章讨论了单向关联的一对多映射,在一的一端维护双向的关系这样的做法尽管能实现可是存在非常多缺陷,首先生成非常多多余的SQL语句,由于多的一端不维护关系,仅仅有一的一端维护,在进行操作时一的一端会发出多余的update语句;其次,由于多的一端不知道一的一端存在,所以在保存多的一端时假设外键为null值,而且在设计数据库时关系字段设为非空,则将无法保存数据。由于单向关联一对多存在非常多缺点那就没有其他的办法了吗,能够採用双向关联来优化。
一、一对多双向关联
这里继续採用上篇文章的学生和班级作为演示样例,班级和学生之间是一对多的关系,一个班级中拥有多名学生,和上篇文章不同的是这里的关系是双向的,也就是一的一端和多的一端同一时候维护关联关系,所以它的对象图例如以下:
相应的关系模型图没有太大的变化,由于它们之间的关系是双向的,所以在关系模型中两端同一时候维护关联关系,映射到关系模型中例如以下图所看到的:
在一对多的单向关联中映射文件仅仅须要在一的一端进行特殊配置就能够,使用<one-to-many>配置,并在对象模型中使用set迭代器来设置外联的对象模型,可是不同的是在双向的关联中须要在多的一端加入相应的还有一端的外键关联,这时候就必须在多的一端使用<many-to-one>的关联关系来标明这样的双向性。
1、映射
这里还使用Classes和Student来做演示样例,在Classes一端的内容和上文同样不会发生变换,可是多的一端Student的配置会发生变化,也就是在映射文件里须要加入<many-to-one>标签。
Student.hbm.xml映射文件配置须要加入外键列<many-to-one>标签,而且该列的名称要和Classes.hbm.xml的外键列的名称一致,详细例如以下代码:
<?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.src.hibernate.Student" table="t_student">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<!-- 在多的一端Student中加入一行新的Classes列 ,而且列的名称要和Classes.hbm.xml的列明同样-->
<many-to-one name="classes" column="classesid"></many-to-one>
</class>
</hibernate-mapping>
Classes.hbm.xml映射文件的配置和上篇文章同样,须要注意的是在Classes.java文件里加入了set属性映射相应了Student对象,所以在映射文件里须要加入set标签来指示为对象模型中使用了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>
<class name="com.src.hibernate.Classes" table="t_classes">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="students" inverse="true">
<key column="classesid"></key>
<one-to-many class="com.src.hibernate.Student"></one-to-many>
</set>
</class>
</hibernate-mapping>
2、类
映射文件的配置是直接相应着类来的,所以有了映射文件就行写出相应的类,同样的有了类就行知道相应的映射文件怎样编写,那来看看相应的类代码怎样编写。
Student.java类,须要在类中加入关联的班级对象属性,在载入Student时能获得Classes的相关信息。
package com.src.hibernate;
public class Student {
//关联的班级对象
private Classes classes;
public Classes getClasses() {
return classes;
}
public void setClasses(Classes classes) {
this.classes = classes;
}
//学生id
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
//学生姓名
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Classes.java文件详细代码内容见上篇文章,这里就不在详述。
有了对象模型接下来生成关系模型,生成的SQL语句例如以下:
alter table t_student drop foreign key FK4B907570FC588BF4
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 FK4B907570FC588BF4 (classesid), add constraint FK4B907570FC588BF4 foreign key (classesid) references t_classes (id)
3、数据操作
建立表结构后来编写測试方法来验证数据的操作,首先来看看数据的插入,向表结构中插入数据,写入数据时会有两种情况,一种是首先创建一个Classes对象,并将对象写入到数据库中,然后创建Student对象,在Classes对象中加入学生对象;第二种是先创建学生对象,并将学生对象写入数据库中,然后创建Classes对象将学生对象加入到Classes对象中,这两种类型的操作最后是不同样的,来对照下。
3.1 先写班级后写学生
先把班级写入到数据库中后,Classes对象进入了Transient状态,并在数据库中有了一行,这时再写Student对象,Student对象会查找相应的Classes的主键将其写入到表中,所以此时关系模型中的数据都是非空的,保存的代码例如以下:
public void testSave(){
Session session=null;
try{
//创建session对象
session=HibernateUtils.getSession();
//开启事务
session.beginTransaction();
//创建班级对象,将班级对象写入到数据库中
Classes classes=new Classes();
classes.setName("class");
session.save(classes);
//创建学生1对象,将学生对象写入到数据库中
Student student1=new Student();
student1.setName("zhangsan");
student1.setClasses(classes);
session.save(student1);
//创建学生2对象,将学生对象写入到数据库中
Student student2=new Student();
student2.setName("lisi");
student2.setClasses(classes);
session.save(student2);
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
相应的写入数据库中的信息列表例如以下图:
3.2 先写学生后写班级
先把学生写入到数据库中此时由于学生表须要获取相应的班级列的主键信息,可是由于班级信息转化到Transient状态,所以在写入学生信息时会有null值,代码例如以下:
public void testSave(){
Session session=null;
try{
//创建session对象
session=HibernateUtils.getSession();
//开启事务
session.beginTransaction();
//创建学生1对象,将学生对象写入到数据库中
Student student1=new Student();
student1.setName("zhangsan");
session.save(student1);
//创建学生2对象,将学生对象写入到数据库中
Student student2=new Student();
student2.setName("lisi");
session.save(student2);
//创建班级对象
Classes classes=new Classes();
classes.setName("Classes");
//设置学生集合
Set students=new HashSet();
students.add(student1);
students.add(student2);
//将学生集合写入到Classes中
classes.setStudents(students);
//能够成功保存数据
//可是会发出多余的update语句来维持关系,由于是一对多的原因
session.save(classes);
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
写入后相应的数据库视图例如以下:
对照两种写入操作,由于两个写入的先后顺序不同所以出现了不同的结果,但由于是双向的关联关系所以在写入时并不会发生异常。
4、读取操作
public void testLoad1(){
Session session=null;
try{
session=HibernateUtils.getSession();
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());
}
//通过学生信息读取班级信息
Student stu=new Student();
stu=(Student)session.load(Student.class, 1);
System.out.println("通过学生载入班级信息Classes.id= "+stu.getClasses().getId());
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=class
Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id0_0_, students0_.name as name0_0_, students0_.classesid as classesid0_0_ from t_student students0_ where students0_.classesid=?
student.name=lisi
student.name=zhangsan
通过学生载入班级信息Classes.id= 1
结语
【Hibernate步步为营】--(一对多映射)之双向关联的更多相关文章
- hibernate一对一外键双向关联
关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...
- hibernate一对一主键双向关联
关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...
- Hibernate一对一外键双向关联(Annotation配置)
如上图所示:一个学生有一个学生证号,一个学生证号对应一名学生.在Hibernate中怎么用Annotation来实现呢? 学生类,主键是id:学生证的主键也是Id: Student.java pack ...
- java之hibernate之多对多双向关联映射
1.比如在权限管理中,角色和权限之间的关系就是多对多的关系,表结构为: 2.类结构 Role.java public class Role implements Serializable{ priva ...
- hibernate多对一双向关联
关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...
- Hibernate多对多双向关联的配置
Hibernate的双向多对多关联有两种配置方法:那我们就来看看两种方案是如何配置的. 一.创建以各自类为类型的集合来关联 1.首先我们要在两个实体类(雇员<Emploee>.工程< ...
- hibernate一对一外键单向关联
关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...
- hibernate一对一主键单向关联
关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...
- 【Hibernate步步为营】--(一对多映射)之单向关联
上篇文章讨论了双向关联的一对一映射,用了两个章节,主要是从主键和外键两种关联映射展开具体讨论.双向关联的映射须要在两个映射文件里分别加入相互的相应关系.斌刚在相应的类中加入相应的关联类的属性.这样在一 ...
随机推荐
- UVA 10820 Send a Table euler_phi功能
除1,1其他外国x,y不等于 为 x<y 案件 一切y有phi(y)组合 F[x]= phi(i) 2<=i<=x 结果为 2*F[x]+1 Problem A Send a Tab ...
- java去全半角空格,trim(), replaceAll(" +",""),replaceAll("\\s*", ""), replaceAll(" | ", "")
JAVA中去掉空格 . String.trim() trim()是去掉首尾空格 .str.replace(" ", ""); 去掉所有空格,包括首尾.中间 St ...
- Android 权限添加
在AndroidMainFest.xml中加上以下代码就行了 添加WiFi以及访问网络的权限: <uses-permission android:name="android.permi ...
- windows phone (15) UI变换上
原文:windows phone (15) UI变换上 在wp中只要是继承自UIElement 的任何对象都可以应用变换,当然包含Textblock,Rectangle等所有的元素,下面我们使用Tex ...
- 三星Samsung 4.4.2该负责人制度,简化名单
installed uninstalled AccessControl.apk AllshareControlShare.apk AirMotionTryActually.apk AllshareFi ...
- eclipse 代码清理 代码格式化 代码凝视
Code Style包含两个方面:代码清理,代码规范化.代码清理能够參考: http://www.ibm.com/developerworks/cn/opensource/os-eclipse-cle ...
- 潜水 java类加载器ClassLoader
类加载器(class loader)用于装载 Java 类到 Java 虚拟机中.一般来说.Java 虚拟机使用 Java 类的方式例如以下:Java 源程序(.java 文件)在经过 Java 编译 ...
- 构建自己的Java并发模型框架
Java的多线程特性为构建高性能的应用提供了极大的方便,可是也带来了不少的麻烦.线程间同步.数据一致性等烦琐的问题须要细心的考虑,一不小心就会出现一些微妙的,难以调试的错误. 另外.应用逻辑和线程逻辑 ...
- shell程序之逐行读取一文件里的參数且使用此參数每次运行5分钟
/********************************************************************* * Author : Samson * Date ...
- Sencha Architect 2 的使用
俗话说的好, 工欲善其事必先利其器, 用Sencha开发的语言, 自己可能不太熟悉, 写出来很麻烦, 于是给大家介绍一个工具. 启动程序第一个界面: 单击第一个Go按钮, 创建一个项目.进入以后, 单 ...