深入解析Java的Hibernate框架中的一对一关联映射

作为一个ORM框架,hibernate肯定也需要满足我们实现表与表之间进行关联的需要。hibernate在关联方法的实现很简单。下面我们先来看看一对一的做法:
 不多说了,我们直接上代码:
 两个实体类,TUser和TPassport:

public class TUser implements Serializable{ 

 private static final long serialVersionUID = 1L;
 private int id;
 private int age;
 private String name;
 private TPassport passport;
  //省略Get/Set方法
}
public class TPassport implements Serializable{ 

 private static final long serialVersionUID = 1L;
 private int id;
 private String serial;
 private int expiry;
 private TUser user;
  //省略Get/Set方法
}

下面我们看一下映射文件有什么不同:

<hibernate-mapping package="org.hibernate.tutorial.domain4">
 <class name="TUser" table="USER4">
  <id name="id" column="id">
   <generator class="native" />
  </id>
  <property name="name" type="java.lang.String" column="name"/>
  <property name="age" type="java.lang.Integer" column="age"/>
  <one-to-one name="passport" class="TPassport"
     cascade="all" outer-join="true" />
 </class>
</hibernate-mapping>

这里我们看到有一个新标签,one-to-one,它表明当前类与所对应的类是一对一的关系,cascade是级联关系,all表明无论什么情况都进行级联,即当对TUser类进行操作时,TPassport也会进行相应的操作,outer-join是指是否使用outer join语句。
 我们再看另外一个TPassport的映射文件:

<hibernate-mapping package="org.hibernate.tutorial.domain4">
 <class name="TPassport" table="passport4">
  <id name="id" column="id">
   <generator class="foreign" >
    <param name="property">user</param>
   </generator>
  </id>
  <property name="serial" type="java.lang.String" column="serial"/>
  <property name="expiry" type="java.lang.Integer" column="expiry"/>
  <one-to-one name="user" class="TUser" constrained="true" />
 </class>
</hibernate-mapping>

这里我们重点看到generator的class值,它为foreign表明参照外键,而参照哪一个是由param来进行指定,这里表明参照User类的id。而one-to-one标签中多了一个constrained属性,它是告诉hibernate当前类存在外键约束,即当前类的ID根据TUser的ID进行生成。
 下面我们直接上测试类,这次测试类没有用JUnit而是直接Main方法来了:

public static void main(String[] args) { 

  Configuration cfg = new Configuration().configure();
  SessionFactory sessionFactory = cfg.buildSessionFactory();
  Session session = sessionFactory.openSession(); 

  session.beginTransaction(); 

  TUser user = new TUser();
  user.setAge(20);
  user.setName("shunTest"); 

  TPassport passport = new TPassport();
  passport.setExpiry(20);
  passport.setSerial("123123123"); 

  passport.setUser(user);
  user.setPassport(passport); 

  session.save(user); 

  session.getTransaction().commit(); 

 }

代码很简单,就不说了。我们主要看这里:

session.save(user);

这里为什么我们只调用一个save呢,原因就在我们的TUser映射文件中的cascade属性,它被设为all,即表明当我们对TUser进行保存,更新,删除等操作时,TPassport也会进行相应的操作,所以这里我们不用写session.save(passport)。我们看到后台:

Hibernate: insert into USER4 (name, age) values (?, ?)
Hibernate: insert into passport4 (serial, expiry, id) values (?, ?, ?) 

Hibernate:   它打印出两个语句,证明hibernate确定帮我们做了这个工作。
 
 
 下面我们再来一个测试类,测试查询:

public static void main(String[] args) {
  Configuration cfg = new Configuration().configure();
  SessionFactory sessionFactory = cfg.buildSessionFactory();
  Session session = sessionFactory.openSession(); 

  TUser user = (TUser)session.load(TUser.class,new Integer(3));
  System.out.println(user.getName()+":"+user.getPassport().getSerial()); 

 }

这里我们通过查询出TUser类,取到TPassport对象。
 我们可以看到hibernate的SQL语句是:

代码如下:

Hibernate:
select tuser0_.id as id0_1_, tuser0_.name as name0_1_, tuser0_.age as age0_1_, tpassport1_.id as id1_0_, tpassport1_.serial as serial1_0_, tpassport1_.expiry as expiry1_0_ from USER4 tuser0_ left outer join passport4 tpassport1_ on tuser0_.id=tpassport1_.id where tuser0_.id=?

我们看到语句当中有left outer join,这是因为我们前面在one-to-one当中设了outer-join="true",我们试着把它改成false,看到SQL语句如下:

代码如下:

Hibernate:
select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.age as age0_0_ from USER4 tuser0_ where tuser0_.id=?

Hibernate:
select tpassport0_.id as id1_0_, tpassport0_.serial as serial1_0_, tpassport0_.expiry as expiry1_0_ from passport4 tpassport0_ where tpassport0_.id=?

现在是分成两条来查了,根据第一条查出的ID再到第二条查出来。
 
 也许很多人会问为什么测试的时候不用TPassport查出TUser呢,其实也可以的,因为它们是一对一的关系,谁查谁都是一样的。

外键关联
现在我们看一下通过外键来进行关联的一对一关联。
 还是一贯的直接上例子:我们写了两个实体类,TGroup和TUser

public class TGroup implements Serializable{ 

 private static final long serialVersionUID = 1L;
 private int id;
 private String name;
 private TUser user;
  //省略Get/Set方法
}
public class TUser implements Serializable{ 

 private static final long serialVersionUID = 1L;
 private int id;
 private int age;
 private String name;
 private TGroup group;
  //省略Get/Set方法 

}

实体类完了我们就看一下映射文件:

<hibernate-mapping package="org.hibernate.tutorial.domain5">
 <class name="TUser" table="USER5">
  <id name="id" column="id">
   <generator class="native" />
  </id>
  <property name="name" type="java.lang.String" column="name"/>
  <property name="age" type="java.lang.Integer" column="age"/>
  <many-to-one name="group" class="TGroup" column="group_id" unique="true" />
 </class>
</hibernate-mapping>

这里我们看到是用many-to-one标签而不是one-to-one,为什么呢?
 这里以前用的时候也没多在注意,反正会用就行,但这次看了夏昕的书终于明白了,实际上这种通过外键进行关联方式只是多对一的一种特殊方式而已,我们通过unique="true"限定了它必须只能有一个,即实现了一对一的关联。
 接下来我们看一下TGroup的映射文件:

<hibernate-mapping package="org.hibernate.tutorial.domain5">
 <class name="TGroup" table="group5">
  <id name="id" column="id">
   <generator class="native" />
  </id>
  <property name="name" type="java.lang.String" column="name"/>
  <one-to-one name="user" class="TUser" property-ref="group" />
 </class>
</hibernate-mapping>

这里,注意,我们又用到了one-to-one,表明当前的实体和TUser是一对一的关系,这里我们不用many-to-one,而是通过one-to-one指定了TUser实体中通过哪个属性来关联当前的类TGroup。这里我们指定了TUser是通过group属性和Tuser进行关联的。property-ref指定了通过哪个属性进行关联。
 下面我们看测试类:

public class HibernateTest { 

 public static void main(String[] args) { 

  Configuration cfg = new Configuration().configure();
  SessionFactory sessionFactory = cfg.buildSessionFactory();
  Session session = sessionFactory.openSession(); 

  session.beginTransaction(); 

  TGroup group = new TGroup();
  group.setName("testGroup"); 

  TUser user = new TUser();
  user.setAge(23);
  user.setName("test"); 

  user.setGroup(group);
  group.setUser(user); 

  session.save(group);
  session.save(user); 

  session.getTransaction().commit();
  session.close();
 } 

}

注意,这次我们的代码中需要进行两次的保存,因为它们对各自都有相应的对应,只保存一个都不会对另外一个有什么操作。所以我们需要调用两次保存的操作。最后进行提交。
 hibernate打印出语句:

Hibernate: insert into group5 (name) values (?)
Hibernate: insert into USER5 (name, age, group_id) values (?, ?, ?)

这说明我们正确地存入了两个对象值。
 
 我们写多一个测试类进行查询:

public static void main(String[] args) { 

  Configuration cfg = new Configuration().configure();
  SessionFactory sessionFactory = cfg.buildSessionFactory();
  Session session = sessionFactory.openSession(); 

  TUser user = (TUser)session.load(TUser.class,new Integer(1));
  System.out.println("From User get Group:"+user.getGroup().getName()); 

  TGroup group = (TGroup)session.load(TGroup.class,new Integer(1));
  System.out.println("From Group get User:" + group.getUser().getName()); 

  session.close(); 

 }

我们都可以得到正确的结果,这表明我们可以通过两个对象拿出对方的值,达到了我们的目的。
 这个例子中用到的TGroup和TUser只是例子而已,实际上现实生活中的user一般都对应多个group。

(0)

相关推荐

  • hibernate一对多关联映射学习小结

    一对多关联映射  映射原理  一对多关联映射和多对一关联映射的映射原理是一致的,都是在多的一端加入一个外键,指向一的一端.关联关系都是由多端维护,只是在写映射时发生了变化. 多对一和一对多的区别 多对一和一对多的区别在于维护的关系不同: (1)多对一:多端维护一端的关系,在加载多端时,可以将一端加载上来. (2)一对多:一端维护多端的关系,在加载一端时,可以将多端加载上来. 分类 一对多单向关联映射 对象模型 从对象模型中,我们可以看出,Group持有User的一个引用.由于是单向关联,所以数据

  • Hibernate映射解析之关联映射详解

    Hibernate中的关联映射 关联关系 平时开发中,类与类之间最普遍的的关系就是关联关系,而且关联是有方向的. 以部门(Dept)和员工(Employee)为例:一个部门下有多个员工,而一个员工只能属于一个部门. 从Employee到Dept的关联就是 多对一 关联. 这就说明 每个Employee对象只会引用一个Dept对象,因此在Employee类中应该定义一个Dept类型的属性,来引用所关联的Dept对象. 从Dept到Employee的关联就是 一对多 关联.这就说明 每个Dept对象

  • Java的Hibernate框架中一对多的单向和双向关联映射

    一.一对多单向关联映射 一对多关系的对象模型在日常生活中也经常看到,就拿学生和班级来说,一个班级里有多个学生,所以班级和学生的关系是一对多的关系,映射到对象模型中,如下图: 对象模型说明了这种一对多的关系是由一的一端来维护的,那么映射成关系模型就是一个班级字段下面会有多个学生,这样就形成了一对多的关系,通过班级能够查询获得学生信息,对应的关系模型如下图: 1.基本配置 有了对象模型接下来就让它们映射为对应的关系代码,在进行关系映射时需要在一的一端添加<one-to-many>标签,另外还需要在

  • Hibernate一对多关联双向关联代码实现分享

    1.创建实体类(Customer.java.Orders.java) 复制代码 代码如下: package wck.stu.vo.oneToMany_single; import java.util.HashSet;import java.util.Set; public class Customer {    private String id = ""; private String cName = ""; private String bank = "

  • java Hibernate 一对多自身关联问题

    Hibernate 一对多自身关联问题 这个很难描述清楚,只能引用CSDN中我提问的帖子了: http://topic.csdn.net/u/20080711/16/7494bf10-48ca-4b2e-8a01-303e647f5516.html 方法,在表单中取得一个PO,然后session.save(po),如下: 程序代码             tx = session.beginTransaction();         session.save(catalog);        

  • 举例讲解Java的Hibernate框架中的多对一和一对多映射

    多对一(Many-to-One)映射 多对一(many-to-one)关联是最常见的关联关系,其中一个对象可以与多个对象相关联.例如,一个相同的地址对象可以与多个雇员的对象相关联. 定义RDBMS表: 考虑一个情况,我们需要员工记录存储在EMPLOYEE表,将有以下结构: create table EMPLOYEE ( id INT NOT NULL auto_increment, first_name VARCHAR(20) default NULL, last_name VARCHAR(20

  • 详解hibernate双向多对多关联映射XML与注解版

    双向多对多关联映射原理: 假设,一个员工可能有多个角色,一个角色可能有多个员工,从员工或角色的角度看,这就是多对多的关系,不管从哪一个角度看,都是多对多的联系.多对多关联映射关系一般采用中间表的形式来实现,即新增一种包含关联双方主键的表.实现多对多关联关系,在数据库底层通过添加中间表指定关联关系,而在hibernate框架在双方的实体中添加一个保存对方的集合,在双方的映射文件中使用<set>元素和<many-to-many>元素进行关联关系的配置. 如下图所示: (1)XML版 R

  • 深入解析Java的Hibernate框架中的一对一关联映射

    作为一个ORM框架,hibernate肯定也需要满足我们实现表与表之间进行关联的需要.hibernate在关联方法的实现很简单.下面我们先来看看一对一的做法:  不多说了,我们直接上代码:  两个实体类,TUser和TPassport: public class TUser implements Serializable{ private static final long serialVersionUID = 1L; private int id; private int age; priva

  • 深入解析Java的Hibernate框架中的持久对象

    一.持久对象生命周期 应用程序在使用Hibernate框架后,创建的持久对象会经历一整套生命周期来完成数据库的操作,其中主要的三个状态分别是瞬态(Transient).持久化(Persistent).脱管(detached).这三种状态的转换是能够在应用程序中控制的,如下图: 为了能清楚的了解这几种状态,这里使用一个实例来查看下这几种状态下对象的不同,下面状态内的代码,具体步骤如下: (1)创建Hibernate_session程序集,并添加像相应的jar包: (2)配置Hibernate,添加

  • 解析Java的Hibernate框架中的持久化类和映射文件

    持久化类 Hibernate的整个概念是采取从Java类属性的值,并将持久到数据库表.一个映射文件Hibernate的帮助确定如何从拉动类的值,并将它们映射与表和相关的域. 其对象或实例将存储在数据库表中的Java类在Hibernate中称为持久化类. Hibernate的效果最好,如果这些类遵循一些简单的规则,也称为普通Java对象(POJO)编程模型.有下列持久化类的主要规则,但是,这些规则并不是必需的. 将所有的持久化Java类需要一个默认的构造函数. 所有类应该包含为了让容易识别对象内H

  • Java的Hibernate框架中复合主键映射的创建和使用教程

    复合主键映射需要在映射配置文件中使用<composite-id>标签,该标签是指将一个类指定为相应的复合主键,它的name属性需要指定类文件中定义的属性值,并在该标签中添加<key-property>子标签. Note:想要使用复合映射必须要将复合主键放到一个类中,也就是讲复合主键属性和其它属性分到两个类中,并将复合主键的类实现接口Serializable,该接口隶属于java.io. 复合主键的映射关系的主键是由多个列复合而成的,对应到数据表中相当的简单,如下图: 1.类文件 这

  • Java的Hibernate框架中集合类数据结构的映射编写教程

    一.集合映射 1.集合小介 集合映射也是基本的映射,但在开发过程中不会经常用到,所以不需要深刻了解,只需要理解基本的使用方法即可,等在开发过程中遇到了这种问题时能够查询到解决方法就可以了.对应集合映射它其实是指将java中的集合映射到对应的表中,是一种集合对象的映射,在java中有四种类型的集合,分别是Set.Map.List还有普通的数组,它们之间有很大的区别: (1)Set,不可以有重复的对象,对象是无序的: (2)List,可以与重复的对象,对象之间有顺序: (3)Map,它是键值成对出现

  • Java的Hibernate框架中用于操作数据库的HQL语句讲解

    上次我们一起学习了用Criteria进行相关的操作,但由于Criteria并不是Hibernate官方推荐的查询方式,我们也并不多用.现在我们来看一下官方推荐的HQL,一起学习一下它的强大.  说是HQL,也就是Hibernate查询语句,和SQL有什么区别呢?一个字母的区别,哈哈.  当然不是这样,HQL和SQL的区别在于思想的不同,HQL是用面向对象的方向进行查询,而SQL则是对数据库二维表进行查询,这里包含的是思想的不同.HQL实际上也是SQL,它由Hibernate帮我们在内部进行转换,

  • Java的Hibernate框架中的组合映射学习教程

    一.组合映射 组合是关联关系的一种特殊情况,是关联关系耦合度最高的一种关系,组合的主对象和子对象拥有相同的生命周期,主对像消亡的话子对象也会消亡.这里使用雇主和用户作为示例,用户和雇主都拥有联系方式属性,如果这里站在对象角度思考的话,常常会把对象模型绘制成为组合的方式,抽象出来一个共同的联系方式类,然后两种人分别包含相应的联系方式对象即可,向应的对象模型时它的对象示例如下图所示: 组合对象模型在生成相应的关系模型后会把对应的子类包含到主表中,所以对应的表结构会将相应的属性生成到对应的表中,相应的

  • Java的Hibernate框架中的双向主键关联与双向外键关联

    一.双向主键关联 双向的主键关联其实是单向一对一主键关联的一种特殊情况,只不过要在关联对象的两端的映射文件中都要进行<one-to-one>的配置,另外还要在主映射的主键一端采用foreign外键关联属性. 这里同样使用Person和IdCard来讨论,一个人对应着一个唯一的身份证,而且一个身份证也唯一映射着一个人,所以这就产生了双向的关联关系,Person的主键同样也是IdCard的主键,分别是主键的同时也是外键,这种关联关系成为双向一对一映射,表现到关系模型中可如下图: 图中的两个表采用了

  • Java的Hibernate框架中的基本映射用法讲解

    Hibernate进行了分类整合发现其实Hibernate分为三大部分:核心对象.映射.HQL,这三大部分开发过程中最常使用,前几篇讨论了核心对象及对象之间的转换方法,接下来讨论Hibernate的映射使用方法.   Hibernate一个重要的功能就是映射,它能够在对象模型和关系模型之间转换,是面向对象编程思想提倡使用的,使用映射程序开发人员只需要关心对象模型中代码的编写.对象和关系数据库之间的映射通常是由XML文档来定义的.这个映射文档被设计为易读的,并且可以手动修改.这种映射关系我总结为下

随机推荐