版权声明:本文为博主原创文章,如需转载请标注转载地址。

博客地址:http://www.cnblogs.com/caoyc/p/5602418.html 

一对一关联,可以分为两种。一种是基于外键的关联,另一种是基于主键的关联。如图

一、基于外键的方式

  

  User.java

 package com.proc.one2one;

 public class User {

     private Integer id;
private String name;
private IdCard card;
public User() {
}
public User(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public IdCard getCard() {
return card;
}
public void setCard(IdCard card) {
this.card = card;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}

  IdCard.java

 package com.proc.one2one;

 public class IdCard {

     private Integer id;
private String cardNo;
private User user;
public IdCard(String cardNo) {
this.cardNo = cardNo;
}
public IdCard() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCardNo() {
return cardNo;
}
public void setCardNo(String cardNo) {
this.cardNo = cardNo;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "IdCard [id=" + id + ", cardNo=" + cardNo + "]";
} }

  

  User.hbm.xml

 <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.proc.one2one">
<class name="User" table="t_user">
<id name="id" type="int" column="id" >
<generator class="native"></generator>
</id>
<property name="name" length="20" not-null="true"></property>
<one-to-one name="card" class="IdCard"></one-to-one>
</class>
</hibernate-mapping>

  

  IdCard.hbm.xml

 <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.proc.one2one">
<class name="IdCard" table="t_idcard">
<id name="id" type="int" column="id" >
<generator class="native"></generator>
</id>
<property name="cardNo" type="string" column="cardNo" length="20" not-null="true"></property>
<many-to-one name="user" column="userid" class="User" unique="true"></many-to-one>
</class>
</hibernate-mapping>

  我们可以看到一个是one-to-one一个是many-to-one的unique。

  分清楚这两个很重要,many-to-one用在保存外键的表,也就是说t_idcard表,one-to-one用在没有保存外键的表,也就是user表.

测试代码:

1、添加关联关系

测试:1:

 public class App {

     private static SessionFactory factory=new Configuration()
.configure()
.addClass(User.class)
.addClass(IdCard.class)
.buildSessionFactory(); @Test
public void test(){ Session session=factory.openSession();
Transaction tx=session.beginTransaction(); User user=new User("caoyc");
IdCard card=new IdCard("510123588413x"); card.setUser(user);
session.save(user);
session.save(card);
tx.commit();
session.close(); }
}

  上面我们通过IdCard来维护关联关系,结果正确

  

测试2:

  下面我们来试一试通过User来维护关联关系,看结果会怎么样?

     @Test
public void test(){ Session session=factory.openSession();
Transaction tx=session.beginTransaction(); User user=new User("caoyc");
IdCard card=new IdCard("510123588413x"); user.setCard(card); session.save(user);
session.save(card);
tx.commit();
session.close(); }

  在数据库中我们可以看到,数据库中表的结构完全一致,而且在t_user中也插入了数据,在t_idcard表中也同样有数据,只不过,t_idcard表中的userid列为null,也就是说,通过user无法维护关联关系

  【总结】:在有外键的一方,可以维护关联关系,而在没有外键的一方无法维护关联关系

测试3:

  我们交换user对象和card对象的保存顺序

 session.save(card);
session.save(user);

  结果数据也能够正常插入到数据库中,结果和测试1相同。那么交换保存顺序是否有其他影响呢?答案是肯定的,虽然数据同样插入进去了,但是在具体插入过程却有不同。

  在测试1中:我们先保存的user,通过insert into语句我们将数据正确插入,然后我们在保存card,而此时的user对象由于已经在数据库中存在,那么必然有主键ID存在,我们在插入到IdCard表中,数据全部完全插入。具体sql语句

 Hibernate: insert into t_user (name) values (?)
Hibernate: insert into t_idcard (cardNo, userid) values (?, ?)

  在测试3中:我们先将card的数据保存到idcard表中,而此时的user的id值为null,所有在插入到idcard中是,userid会是nul

  l

  然后在插入user到t_user表中,那么此时user的主键值已经生成。为了维护关联关系

  系统会有执行一条语句

  update t_idcard set cardNo=?, userid=? where id=?

  所有在测试3中,我们会看到

 Hibernate: insert into t_idcard (cardNo, userid) values (?, ?)
Hibernate: insert into t_user (name) values (?)
Hibernate: update t_idcard set cardNo=?, userid=? where id=?

  【总结】:在保存数据时,我们先保存没有外键的一方,然后在保存有外键的一方,这样执行效率更高

2、解除关联关系

测试1:通过User来解除关联关系

     @Test
public void test(){ Session session=factory.openSession();
Transaction tx=session.beginTransaction(); User user=session.get(User.class, 1);
user.setCard(null); tx.commit();
session.close(); }

  执行的SQL语句

Hibernate: select user0_.id as id1_1_0_, user0_.name as name2_1_0_, idcard1_.id as id1_0_1_, idcard1_.cardNo as cardNo2_0_1_, idcard1_.userid as userid3_0_1_ from t_user user0_ left outer join t_idcard idcard1_ on user0_.id=idcard1_.id where user0_.id=?

  可以看到,此时通过user无法来解除关联关系

测试2:通过idcard来解除关联关系

     @Test
public void test(){ Session session=factory.openSession();
Transaction tx=session.beginTransaction(); IdCard card=session.get(IdCard.class, 1);
card.setUser(null); tx.commit();
session.close(); }

  执行的SQL语句

 Hibernate: select idcard0_.id as id1_0_0_, idcard0_.cardNo as cardNo2_0_0_, idcard0_.userid as userid3_0_0_ from t_idcard idcard0_ where idcard0_.id=?
Hibernate: update t_idcard set cardNo=?, userid=? where id=?

  在数据库中也可看到通过idcard的确能够解除关联关系

3、删除操作

测试1:删除user

     @Test
public void test(){ Session session=factory.openSession();
Transaction tx=session.beginTransaction(); User user=session.get(User.class, 1);
session.delete(user); tx.commit();
session.close(); }

  如果此时将要删除的user数据在t_idcard表中没有对应相应的数据,那么可以删除成功,否则将会抛出异常,意思说有外键约束,该数据无法删除

测试2:删除idcard

     public void test(){

         Session session=factory.openSession();
Transaction tx=session.beginTransaction();
IdCard card=session.get(IdCard.class, 1);
session.delete(card);
tx.commit();
session.close();
}

  结果:删除成功

Question:在上面测试2中,我们删除了t_idcard中的数据,如果我需要当删除了t_idcard中的数据后,同样删除t_user中对应的属性,我们该怎么办呢?

Answer: 那么我们需要设置cascade属性为delete,我们在IdCard.hbm.xml

<many-to-one name="user" column="userid" class="User" unique="true" cascade="delete"></many-to-one>

也就是说,我们在删除对象idCard是,同样对其属性user也做删除动作

外键方式总结:

  1、在有外键的一方,可以维护关联关系,可以建立关联关系,同样也可以解除关联关系,可以任意删除本对象,如果在hbm.xml中设置了cascade="delete",也可以删除关联对象

  2、在没有外键的一方,不可以维护关联关系,所有无法建立关联关系,也无法解除关联关系。在删除过程中,如有没有外键值对应本条数据,可以成功删除,否则会抛出异常

  

二、基于主键的关联方式

  基于外键方式:一个many-to-one(有外键方)和一个one-to-one(无外键方法)

  基于主键方式:两个都是one-to-one

  还是上面的例子,其它我们都不需要改变,我们只需要改变IdCard.hbm.xml就可以,具体代码如下

 <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.proc.one2one">
<class name="IdCard" table="t_idcard">
<id name="id" type="int" column="id" >
<generator class="foreign">
<param name="property">user</param>
</generator>
</id>
<property name="cardNo" type="string" column="cardNo" length="20" not-null="true"></property>
<one-to-one name="user" class="User" constrained="true"></one-to-one>
</class>
</hibernate-mapping>

  代码说明:

    1、由于是基于主键方式,所有对应t_idcard表的主键id也是来自于t_user表,所有对应IdCard主键生成策略我们选用foregin,其中还必须指定一个从参数property,表示该主键生成策略基于对象的那个属性,我们这里的属性是user

    2、constrained="true":表示给t_idcard添加一个外键约束,默认为false,不添加外键约束

Hibernate 一对一关联查询的更多相关文章

  1. 一对一关联查询时使用relation连贯操作查询后,调用getLastSql()方法输出的sql语句

    如题: 一对一关联查询时使用relation连贯操作查询后,调用getLastSql()方法输出的sql语句不是一条关联查询语句. 例如: $list = $db->relation(true) ...

  2. MyBatis从入门到放弃三:一对一关联查询

    前言 简单来说在mybatis.xml中实现关联查询实在是有些麻烦,正是因为起框架本质是实现orm的半自动化. 那么mybatis实现一对一的关联查询则是使用association属性和resultM ...

  3. MyBatis:一对一关联查询

    MyBatis从入门到放弃三:一对一关联查询 前言 简单来说在mybatis.xml中实现关联查询实在是有些麻烦,正是因为起框架本质是实现orm的半自动化. 那么mybatis实现一对一的关联查询则是 ...

  4. Mybatis学习4——一对一关联查询方法2------实体作为属性

    实体order和user采用resultMap order package pojo; import java.util.Date; public class Order { private Inte ...

  5. Mybatis学习4——一对一关联查询方法1--创建实体

    创建一个实体继承两个实体之一,另一个实体作为属性 实体1. order package pojo; import java.util.Date; public class Order { privat ...

  6. MyBatis关联查询,一对一关联查询

    数据库E-R关系 实体类 public class City { Long id; String name; Long countryId; Date lastUpdate; } public cla ...

  7. mybatis 使用接口增删改查和两表一对一关联查询

    导包 总配置文件 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration ...

  8. MyBatis学习(四)MyBatis一对一关联查询

    一对一关联查询即.两张表通过外键进行关联.从而达到查询外键直接获得两张表的信息.本文基于业务拓展类的方式实现. 项目骨架 配置文件conf.xml和db.properties前几节讲过.这里就不细说了 ...

  9. 04.Hibernate一对一关联

        前言:本文主要介绍使用Hibernate映射一对一的关联关系的两种方式:使用外键映射.使用主键映射. 1.数据库表的一对一关联关系     本文根据客户信息表(tb_customer)和地址信 ...

随机推荐

  1. 静态call 动态call LINK

    COBOL的调用可以是静态调用(Static Call),这时,被调用的子程序必须与调用程序一起链接(link-edited)起来形成一个完整的装载模块(Load module),但子程序依然可以单独 ...

  2. poj 2940

    Wine Trading in Gergovia Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3187   Accepte ...

  3. Polynomial Problem(hdu 1296 表达式求值)

    We have learned how to obtain the value of a polynomial when we were a middle school student. If f(x ...

  4. 【博弈论】【SG函数】【线段树】Petrozavodsk Summer Training Camp 2016 Day 9: AtCoder Japanese Problems Selection, Thursday, September 1, 2016 Problem H. Cups and Beans

    一开始有n个杯子,每个杯子里有一些豆子,两个人轮流操作,每次只能将一个豆子移动到其所在杯子之前的某个杯子里,不过可以移动到的范围只有一段区间.问你是否先手必胜. 一个杯子里的豆子全都等价的,因为sg函 ...

  5. 【DFS】【枚举】Gym - 101246G - Revolutionary Roads

    给你一张有向图,问你将任意一条边变成双向后,所能得到的最大强连通分量的大小. 缩点之后,预处理can(i,j)表示i能到j. 之后枚举每一条边(u,v),再枚举其他所有点t,如果can(u,t) &a ...

  6. 从源码入手,一文带你读懂Spring AOP面向切面编程

    之前<零基础带你看Spring源码--IOC控制反转>详细讲了Spring容器的初始化和加载的原理,后面<你真的完全了解Java动态代理吗?看这篇就够了>介绍了下JDK的动态代 ...

  7. Java编程思想学习(二)----一切都是对象

    2.1用应用操作对象 String s; 这里所创建的只是引用,并不是对象.如果此时向s发送一个消息,就会返回一个运行时错误.这是因为此时s没有和任何事物关联.因此,一种安全的做法是:创建一个引用的同 ...

  8. xml和集合混合使用-图书管理器

    package com.book; public class Book { private int id; //图书编号 private String name; //图书名称 private Str ...

  9. 简单理解SNAT回流中的概念:路由器怎么知道外网返回的数据是局域网中哪台主机的

    内网到外网用的是NAT技术(地址封装)外网到内网用的是端口映射(PNAT)计算机的端口又65535(0-65534),你说的那些有名气的端口大多都是0-1023之间的你说的这个问题很简单,但首先你要懂 ...

  10. Mac下php 5升级到php 7的步骤详解

    前言 在MAC OS X 10.11中php的版本是5.5的,近来一年多里,看到了很多关于php7介绍,以为php7增加了很多新特性,也删除了原来很多的老特性,所以一直以来并没想去尝试使用php7,但 ...