双向一对一的关联关系

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

其实体属性定义如下:

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

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

  10. //省略getter、setter方法...
  11.  
  12. }

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

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

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

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

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

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

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

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

再讲一下映射的默认属性,同上面一样由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注解)

  1. package com.magicode.jpa.doubl.one2one;
  2.  
  3. import javax.persistence.Column;
  4. import javax.persistence.Entity;
  5. import javax.persistence.GeneratedValue;
  6. import javax.persistence.Id;
  7. import javax.persistence.OneToOne;
  8. import javax.persistence.Table;
  9.  
  10. @Table(name="t_department")
  11. @Entity
  12. public class Department {
  13.  
  14. private Integer id;
  15. private String deptName;
  16.  
  17. private Manager mgr;
  18.  
  19. @Column(name="ID")
  20. @GeneratedValue
  21. @Id
  22. public Integer getId() {
  23. return id;
  24. }
  25.  
  26. @Column(name="DEPT_NAME", length=25)
  27. public String getDeptName() {
  28. return deptName;
  29. }
  30.  
  31. /**
  32. * 通过mapptedBy指定由关联对象的那个属性建立起连接
  33. * Manger实体对应的数据表没有外键,无法使用延迟加载策略
  34. * 所以使用默认的检索方式就好。
  35. * 如果设置了fetch=FetchType.LAZY反而会多发送一条sql语句。
  36. */
  37. @OneToOne(mappedBy="dept")
  38. public Manager getMgr() {
  39. return mgr;
  40. }
  41.  
  42. @SuppressWarnings("unused")
  43. private void setId(Integer id) {
  44. this.id = id;
  45. }
  46.  
  47. public void setDeptName(String deptName) {
  48. this.deptName = deptName;
  49. }
  50.  
  51. public void setMgr(Manager mgr) {
  52. this.mgr = mgr;
  53. }
  54. }

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

  1. package com.magicode.jpa.doubl.one2one;
  2.  
  3. import javax.persistence.Column;
  4. import javax.persistence.Entity;
  5. import javax.persistence.FetchType;
  6. import javax.persistence.GeneratedValue;
  7. import javax.persistence.Id;
  8. import javax.persistence.JoinColumn;
  9. import javax.persistence.OneToOne;
  10. import javax.persistence.Table;
  11.  
  12. @Table(name="t_manager")
  13. @Entity
  14. public class Manager {
  15.  
  16. private Integer id;
  17. private String mgrName;
  18.  
  19. private Department dept;
  20.  
  21. @Column(name="ID")
  22. @GeneratedValue
  23. @Id
  24. public Integer getId() {
  25. return id;
  26. }
  27.  
  28. @Column(name="MGR_NAME", length=25)
  29. public String getMgrName() {
  30. return mgrName;
  31. }
  32.  
  33. /**
  34. * 默认情况下对Department属性的检索采用立即检索策略。
  35. * 由于Manager实体对应的数据表有外键列,所以可以设置
  36. * fetch=FetchType.LAZY来修改为延迟加载策略。
  37. *
  38. * 注意:对没有外键类的一方(Department一方)则无法实现
  39. * 延迟加载策略。设置 fetch=FetchType.LAZY以后反而会
  40. * 多发送一条sql语句。
  41. */
  42. @JoinColumn(name="DEPT_ID", unique=true)
  43. @OneToOne(fetch=FetchType.LAZY)
  44. public Department getDept() {
  45. return dept;
  46. }
  47.  
  48. @SuppressWarnings("unused")
  49. private void setId(Integer id) {
  50. this.id = id;
  51. }
  52.  
  53. public void setMgrName(String mgrName) {
  54. this.mgrName = mgrName;
  55. }
  56.  
  57. public void setDept(Department dept) {
  58. this.dept = dept;
  59. }
  60.  
  61. }

List_7. 测试代码:

  1. package com.magicode.jpa.doubl.one2one;
  2.  
  3. import javax.persistence.EntityManager;
  4. import javax.persistence.EntityManagerFactory;
  5. import javax.persistence.EntityTransaction;
  6. import javax.persistence.Persistence;
  7.  
  8. import org.junit.After;
  9. import org.junit.Before;
  10. import org.junit.Test;
  11.  
  12. public class DoubleOne2OneTest {
  13.  
  14. private EntityManagerFactory emf = null;
  15. private EntityManager em = null;
  16. private EntityTransaction transaction = null;
  17.  
  18. @Before
  19. public void before(){
  20. emf = Persistence.createEntityManagerFactory("jpa-1");
  21. em = emf.createEntityManager();
  22. transaction = em.getTransaction();
  23. transaction.begin();
  24. }
  25.  
  26. @After
  27. public void after(){
  28. transaction.commit();
  29. em.close();
  30. emf.close();
  31. }
  32.  
  33. @Test
  34. public void testPersist(){
  35. Department dept = new Department();
  36. dept.setDeptName("Dept-AA");
  37.  
  38. Manager mgr = new Manager();
  39. mgr.setMgrName("Mgr-AA");
  40.  
  41. //创建关联关系
  42. dept.setMgr(mgr);
  43. mgr.setDept(dept);
  44.  
  45. /**
  46. * 持久化的时候,先持久化没有外键的那个对象,在持久化有
  47. * 外间的对象。这样就会避免发送update语句。
  48. */
  49. em.persist(dept);
  50. em.persist(mgr);
  51. }
  52.  
  53. @Test
  54. public void testFind(){
  55. /**
  56. * 默认情况下,双向1-1关联关系中,在检索的时候都采用立即
  57. * 检索的策略(通过左外连接的方式查找与其相关联的属性)。
  58. *
  59. * 有外键的那一方实体可以通过设置@OneToOne注解的fetch=FetchType.LAZY来
  60. * 修改默认检索策略。将其设置为延迟加载(对实体对象索引的检索)。
  61. *
  62. * 对于没有外键的那一方而言,我们不需要修改其默认的检索方式。因为,无论你是否设置
  63. * fetch=FetchType.LAZY都会立即加载其关联的那一方实体(其没有对应的外键列,
  64. * 如果在检索的时候不加载,以后就无法找到其关联的实体对象了)。
  65. * 而且,如果设置了fetch=FetchType.LAZY还会稍微的有一点儿影响性能:默认情况下
  66. * 采用左外连接的方式,只会发送一条sql语句;而如果设置了fetch=FetchType.LAZY
  67. * 则会发送两条sql语句。
  68. */
  69. // Manager mgr = em.find(Manager.class, 2);
  70. // System.out.println(mgr.getMgrName());
  71. // System.out.println(mgr.getDept().getClass().getName());
  72. //
  73. // System.out.println("--------------->");
  74.  
  75. Department dept = em.find(Department.class, 3);
  76. // System.out.println(dept.getDeptName());
  77. // System.out.println(dept.getMgr().getClass().getName());
  78.  
  79. }
  80.  
  81. }

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. SVN四部曲之SVN简单使用教程入门

    1.        签出源代码到本机 在本机创建文件夹StartKit,右键点击Checkout,弹出如下图的窗体: 2.        2 在上图中URL of Repository:下的文本框中输 ...

  2. H5不能少的功能-滑动分页

    // 滑动分页 $(window).scroll(function() {                   var mayLoadContent = $(window).scrollTop() & ...

  3. CP="CAO PSA OUR" 用P3P header解决iframe跨域访问cookie

    1.IE浏览器iframe跨域丢失Session问题 在开发中,我们经常会遇到使用Frame来工作,而且有时是为了跟其他网站集成,应用到多域的情况下,而Iframe是不能保存Session的因此,网上 ...

  4. 微信/QQ机器人的实现

    介绍: Mojo-Webqq和Mojo-Weixin是在github上基于webQQ和网页版WeiXin,用Perl语言实现的开源的客户端框架,它通过插件提供基于HTTP协议的api接口供其他语言或系 ...

  5. 基础才是重中之重~理解linq中的groupby

    linq将大部分SQL语句进行了封装,这使得它们更加面向对象了,对于开发者来说,这是一件好事,下面我从基础层面来说一下GroupBy在LINQ中的使用. 对GroupBy的多字段分组,可以看我的这篇文 ...

  6. KAFKA分布式消息系统

    2015-01-05 大数据平台 Hadoop大数据平台 基本概念 kafka的工作方式和其他MQ基本相同,只是在一些名词命名上有些不同.为了更好的讨论,这里对这些名词做简单解释.通过这些解释应该可以 ...

  7. Android-Empty-Layout:展示不同类型的页面布局,用于视图是空的时候

    Android-Empty-Layout:这个布局可以作用在Listview,Gridview,用于显示数据的是空的时候,可以提示友好的页面.这库可以显示页面出错,页面加载,页面是空. 加载的动画页面 ...

  8. [CF]codeforces round#366(div2)滚粗记

    开场心理活动:啊打完这场大概有1700了吧 中途心理活动:啊这个ABC看起来都随便做啊 死亡原因:欸怎么没网了 -75 .. A [题意]Hulk说完一句I hate会说that I love 然后是 ...

  9. C# 虚方法 与 隐藏方法(new) 区别

    重写和隐藏的定义: 重写:继承时发生,在子类中重新定义父类中的方法,子类中的方法和父类的方法是一样的          例如:基类方法声明为virtual(虚方法),派生类中使用override申明此 ...

  10. lunux 启动 tomcat

    本人从官网http://tomcat.apache.org/上面下载的6.0.1_31版本,并解压包后改名存放在:/usr/share/tomcat6 本人使用的是root用户登录,下面就说说具体的操 ...