博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
9、JPA_映射双向一对一的关联关系
阅读量:6603 次
发布时间:2019-06-24

本文共 6685 字,大约阅读时间需要 22 分钟。

 

双向一对一的关联关系

举例说明:经理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 11     //省略getter、setter方法...12 }
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 11     //省略getter、setter方法...12 13 }

 

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

这里讲使用较多的基于外键的映射。其映射步骤如下(例子中假定由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)@OneToOnepublic Department getDept() {    return dept;}

 

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

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

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 @Entity12 public class Department {13     14     private Integer id;15     private String deptName;16     17     private Manager mgr;18 19     @Column(name="ID")20     @GeneratedValue21     @Id22     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属性指定表的外键列的列名,同时指定外键列的唯一约束)

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")@Entitypublic 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());                    }}

 

转载于:https://www.cnblogs.com/lj95801/p/5011137.html

你可能感兴趣的文章
使用CSVDE批量创建和修改域用户
查看>>
为什么在SharePoint站点上方把我的名字显示成“系统帐户”?
查看>>
【实战】烂泥:解决无法找到"txfile:platformres:msgmgr\msgmgr.htm"
查看>>
《图论》——图的存储与遍历(Java)
查看>>
一招一式攻克linux(三)
查看>>
IT运维管理——流程与表单定义
查看>>
WP下ListBox的绑定和效果
查看>>
Powershell管理系列(三十一)PowerShell操作之批量创建邮箱
查看>>
【REACT NATIVE 系列教程之十】真机运行报错COMMAND /BIN/SH FAILED WITH EXIT CODE 1 的解决方法...
查看>>
SEO外链算法独家揭秘
查看>>
[MySQL优化案例]系列 -- OPTIMIZE的威力
查看>>
Apache2 之虚拟主机设置指南
查看>>
Linux系统开机过程解释笔记
查看>>
js实现购物车数量的自增与自减
查看>>
沟通、务实、平等——读《Scrum and XP from the Trenches》
查看>>
Android java.lang.NoClassDefFoundError 的解决办法
查看>>
UIWebview与js交互[转]
查看>>
Windows Azure Cloud Service (26) Windows Azure 性能监视器
查看>>
swift:高级运算符(位运算符、溢出运算符、优先级和结合性、运算符重载函数)...
查看>>
用户空间缺页异常pte_handle_fault()分析--(上)【转】
查看>>