双向一对一的关联关系

举例说明:经理Manager和部门Department是双向一对一关联关系。则Manager实体类中有Department实体对象的引用,反之亦然。

其实体属性定义如下:

List_1. Manager实体类属性定义(有对Department实体对象的引用)
 @Table(name="t_manager")
@Entity
public class Manager { private Integer id;
private String mgrName; //有对实体Department对象的引用
private Department dept;

//省略getter、setter方法...
}
List_2. Department实体类属性定义(有对Manager实体对象的引用)
 @Table(name="t_department")
@Entity
public class Department { private Integer id;
private String deptName; //有对Manager实体对象的引用
private Manager mgr;

//省略getter、setter方法... }

双向一对一的关联关系映射方法有两种:基于外键的映射、基于主键的映射。

这里讲使用较多的基于外键的映射。其映射步骤如下(例子中假定由Manager一方维护关联关系,Department一方放弃维护关联关系):

1、双方都使用使用@OneToOne注解来映射关联关系;

2、只需要一方维护关联关系(任何一方都可以):

①、放弃维护关联关系的一方需要配置@OneToOne的mappedBy属性,用于指定由对方的哪个属性来映射,同时不能使用@JoinColum注解(和前面讲的双向一对多关联关系是一样的)。放弃维护关联关系的一方所对应的数据表没有外键列。如下Department实体中的映射注解:

List_3. Department实体类的映射注解(放弃维护关联关系,指定由对方的dept属性来进行关联;不能使用@JoinColumn注解)
@OneToOne(mappedBy="dept")
public Manager getMgr() {
return mgr;
}

②、维护关联的一方需要使用@JoinColumn注解来指定外键列的列名,同时还要指定外键列的唯一约束:@JoinColumn(name="DEPT_ID", unique=true)。维护关联关系的一方实体对应的数据表有一个外键列,列名由name属性指定。如下Manager实体类中的映射注解:

List_4. Manager实体类的映射注解(由@JoinColumn注解的name属性指定表的外键列的列名,同时指定外键列的唯一约束)
@JoinColumn(name="DEPT_ID", unique=true)
@OneToOne
public Department getDept() {
return dept;
}

再讲一下映射的默认属性,同上面一样由Manager一方维护关联关系:

1、默认情况下,双方对实体类对象的引用均采用立即加载的检索策略,这是符合前面 8、双向一对多关联关系 一节所阐述的“默认情况下,对象属性采用立即检索,集合属性采用延迟检索”。

2、修改默认检索策略:

①、维护关联关系的一方(如Manager)所对应的数据表有外键列,可以通过设置@OneToOne的属性fetch=FetchType.LAZY来设置延迟加载策略。

②、放弃维护关联关系的一方(如Department)所对应的数据表中没有外键,即便设置了fetch=FetchType.LAZY也不能够达到延迟加载的效果。相反,如果设置了fetch=FetchType.LAZY以后还会多发送一条sql语句(两条select语句);没有设置的时候,只发送一条sql语句(一条带left outer join的select语句)。

3、保存顺序,先保存放弃维护关联关系的一方实体,后保存维护关联关系的一方实体。这样可以避免发送update语句。

下面是实验代码清单:

List_5. Department实体(放弃维护关联关系,指定由对方的dept属性来进行关联;不能使用@JoinColumn注解)

 package com.magicode.jpa.doubl.one2one;

 import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table; @Table(name="t_department")
@Entity
public class Department { private Integer id;
private String deptName; private Manager mgr; @Column(name="ID")
@GeneratedValue
@Id
public Integer getId() {
return id;
} @Column(name="DEPT_NAME", length=25)
public String getDeptName() {
return deptName;
} /**
* 通过mapptedBy指定由关联对象的那个属性建立起连接
* Manger实体对应的数据表没有外键,无法使用延迟加载策略
* 所以使用默认的检索方式就好。
* 如果设置了fetch=FetchType.LAZY反而会多发送一条sql语句。
*/
@OneToOne(mappedBy="dept")
public Manager getMgr() {
return mgr;
} @SuppressWarnings("unused")
private void setId(Integer id) {
this.id = id;
} public void setDeptName(String deptName) {
this.deptName = deptName;
} public void setMgr(Manager mgr) {
this.mgr = mgr;
}
}

List_6. Manager实体(由@JoinColumn注解的name属性指定表的外键列的列名,同时指定外键列的唯一约束)

package com.magicode.jpa.doubl.one2one;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table; @Table(name="t_manager")
@Entity
public class Manager { private Integer id;
private String mgrName; private Department dept; @Column(name="ID")
@GeneratedValue
@Id
public Integer getId() {
return id;
} @Column(name="MGR_NAME", length=25)
public String getMgrName() {
return mgrName;
} /**
* 默认情况下对Department属性的检索采用立即检索策略。
* 由于Manager实体对应的数据表有外键列,所以可以设置
* fetch=FetchType.LAZY来修改为延迟加载策略。
*
* 注意:对没有外键类的一方(Department一方)则无法实现
* 延迟加载策略。设置 fetch=FetchType.LAZY以后反而会
* 多发送一条sql语句。
*/
@JoinColumn(name="DEPT_ID", unique=true)
@OneToOne(fetch=FetchType.LAZY)
public Department getDept() {
return dept;
} @SuppressWarnings("unused")
private void setId(Integer id) {
this.id = id;
} public void setMgrName(String mgrName) {
this.mgrName = mgrName;
} public void setDept(Department dept) {
this.dept = dept;
} }

List_7. 测试代码:

package com.magicode.jpa.doubl.one2one;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence; import org.junit.After;
import org.junit.Before;
import org.junit.Test; public class DoubleOne2OneTest { private EntityManagerFactory emf = null;
private EntityManager em = null;
private EntityTransaction transaction = null; @Before
public void before(){
emf = Persistence.createEntityManagerFactory("jpa-1");
em = emf.createEntityManager();
transaction = em.getTransaction();
transaction.begin();
} @After
public void after(){
transaction.commit();
em.close();
emf.close();
} @Test
public void testPersist(){
Department dept = new Department();
dept.setDeptName("Dept-AA"); Manager mgr = new Manager();
mgr.setMgrName("Mgr-AA"); //创建关联关系
dept.setMgr(mgr);
mgr.setDept(dept); /**
* 持久化的时候,先持久化没有外键的那个对象,在持久化有
* 外间的对象。这样就会避免发送update语句。
*/
em.persist(dept);
em.persist(mgr);
} @Test
public void testFind(){
/**
* 默认情况下,双向1-1关联关系中,在检索的时候都采用立即
* 检索的策略(通过左外连接的方式查找与其相关联的属性)。
*
* 有外键的那一方实体可以通过设置@OneToOne注解的fetch=FetchType.LAZY来
* 修改默认检索策略。将其设置为延迟加载(对实体对象索引的检索)。
*
* 对于没有外键的那一方而言,我们不需要修改其默认的检索方式。因为,无论你是否设置
* fetch=FetchType.LAZY都会立即加载其关联的那一方实体(其没有对应的外键列,
* 如果在检索的时候不加载,以后就无法找到其关联的实体对象了)。
* 而且,如果设置了fetch=FetchType.LAZY还会稍微的有一点儿影响性能:默认情况下
* 采用左外连接的方式,只会发送一条sql语句;而如果设置了fetch=FetchType.LAZY
* 则会发送两条sql语句。
*/
// Manager mgr = em.find(Manager.class, 2);
// System.out.println(mgr.getMgrName());
// System.out.println(mgr.getDept().getClass().getName());
//
// System.out.println("--------------->"); Department dept = em.find(Department.class, 3);
// System.out.println(dept.getDeptName());
// System.out.println(dept.getMgr().getClass().getName()); } }

9、JPA_映射双向一对一的关联关系的更多相关文章

  1. JPA中实现双向一对一的关联关系

    场景 JPA入门简介与搭建HelloWorld(附代码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103473937 ...

  2. 10、JPA_映射双向多对多的关联关系

    双向多对多的关联关系 双向多对多的关联关系(抽象成A-B)具体体现:A中有B的集合的引用,同时B中也有对A的集合的引用.A.B两个实体对应的数据表靠一张中间表来建立连接关系. 同时我们还知道,双向多对 ...

  3. JPA_映射双向多对多的关联关系(转)

    双向多对多的关联关系 转自(http://www.cnblogs.com/lj95801/p/5011537.html) 双向多对多的关联关系(抽象成A-B)具体体现:A中有B的集合的引用,同时B中也 ...

  4. Hibernate之基于外键映射的一对一(1-1)关联关系

    1.对于基于外键的1-1关联,其外键可以存放在任意一边,在需要存放外键一端,增加many-to-one元素.为many-to-one元素增加unique="true"属性来表示为1 ...

  5. JPA学习笔记(8)——映射双向一对多关联关系

    双向一对多关联关系 前面的博客讲的都是单向的,而本问讲的是双向的(双向一对多 = 双向多对一) 什么是双向? 我们来对照一下单向和双向 单向/双向 User实体类中是否有List< Order& ...

  6. JPA学习(四、JPA_映射关联关系)

    框架学习之JPA(四) JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中 ...

  7. JPA(七):映射关联关系------映射双向多对一的关联关系

    映射双向多对一的关联关系 修改Customer.java package com.dx.jpa.singlemanytoone; import java.util.Date; import java. ...

  8. Hibernate关系映射(二) 基于外键的双向一对一

    基于外键的双向一对一关联映射 需要在一端添加<one-to-one>标签,用property-ref来指定反向属性引用. 还是通过刚才用户和地址来演示双向一对一关联. 代码演示 一.实体类 ...

  9. Hibernate学习(二补充)关系映射----基于外键的双向一对一

    刚刚写的是基于外键的单向一对一.  那么双向一对一就是在单向一对一的基础上稍微改动就可以了. account.java和account.hbm.xml都不用变动  只要我们小小的变动address.j ...

随机推荐

  1. 【转】微软MVP攻略 (如何成为MVP?一个SQL Server MVP的经验之谈)

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 初衷 什么是微软MVP? 成为微软MVP的条件? 如何成为微软MVP? (一) 申请时间划分 (二) 前期准备 (三) ...

  2. 【转】char*,const char*和string的相互转换

    1. string转const char* string s = "abc"; const char* c_s = s.c_str(); 2. const char*转string ...

  3. 《自学C语言》初级教程 - 目录

    我现在打算出一个C语言学习教程,目的是为了让初学者能够很容易和更深刻地理解C语言. 你可能有这样的疑问,网上不是有很多的初级教程吗,我需要这个吗?我的回答是:网上的C语言教程讲得不够全面,而且许多的初 ...

  4. ubuntu14.04 安装matlab r2013a

    神奇的linux. 进入主题:matlab相信是不少工程人员缺少不了的工具,就我所在的通信行业更是如此,matlab的linux版本是和windows版本同步更新, 不过r2012之后只提供64位版本 ...

  5. 微软职位内部推荐-SDE2 (Windows - Audio)

    微软近期Open的职位: SDE2 (Windows - Audio) Windows Partner Enablement team in Operating System Group is loo ...

  6. Cocos2D-x搭建新环境注意事项

    网上资源都说安装Python后, 设置环境变量, 解压Cocos2Dx压缩包就OK, 但运行CppTest还是会报错, 以下是错误解决方案: 1. 错误提示 error LNK1123: failur ...

  7. Openmeeting 网页打开缓慢,视频卡的一个解决方法

    在初次安装完openmeeting以后,从浏览器打开后发现网页缓慢,视频有卡顿的现象. 原因:为openmeeting分配的内存太小. 解决方法: 找到根目录的red5.bat,打开后查找“set J ...

  8. 2876: [Noi2012]骑行川藏 - BZOJ

    Description 蛋蛋非常热衷于挑战自我,今年暑假他准备沿川藏线骑着自行车从成都前往拉萨.川藏线的沿途有着非常美丽的风景,但在这一路上也有着很多的艰难险阻,路况变化多端,而蛋蛋的体力十分有限,因 ...

  9. uoj 67 新年的毒瘤 割点

    题目链接: 题目 #67. 新年的毒瘤 问题描述 辞旧迎新之际,喜羊羊正在打理羊村的绿化带,然后他发现了一棵长着毒瘤的树. 这个长着毒瘤的树可以用 nn 个结点 mm 条无向边的无向图表示.这个图中有 ...

  10. 多线程Java Socket编程示例(转)

    这篇做为学习孙卫琴<<Java网络编程精解>>的学习笔记吧.其中采用Java 5的ExecutorService来进行线程池的方式实现多线程,模拟客户端多用户向同一服务器端发送 ...