9、JPA_映射双向一对一的关联关系
2015-12-01 19:56
453 查看
双向一对一的关联关系
举例说明:经理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) @OneToOnepublic 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()); } }
相关文章推荐
- Tomcat启动时卡在“INFO: Deploying web application directory ”
- nyoj--20--吝啬的国度(搜索dfs)
- 用dygraphs图表分析xdebug的trace结果
- mapreduce 顺序组合
- leetcode Range Sum Query - Mutable
- 如何修改oracle时区
- 如何修改oracle时区
- 如何修改oracle时区
- PAT Basic 1009
- html通过JavaScript调用java代码
- UNIX环境编程学习笔记------编程实例----扫描一个网段的端口
- 部署web项目时遇到的一个问题
- spark Sql
- 蓝桥杯OJ刷题日记——11-基础练习 十六进制转十进制
- [Kerberos] How to Kerberize an Hadoop Cluster
- git + tortoisegit安装及配置
- AP 1532E register Cisco 2504 AP注册WLC
- 深度图像补洞算法模板
- hdu1438 递推
- Python:计算一段代码的执行时间