1.对于基于外键的1-1关联,其外键可以存放在任意一边,在需要存放外键一端,增加many-to-one元素。为many-to-one元素增加unique=“true”属性来表示为1-1关联
<many-to-one name="mgr" class="com.elgin.hibernate.one2one.foreign.Manager"> <column name="MGRID" unique="true"></column> </many-to-one>
2.另一端需要使用one-to-one元素,该元素使用property-ref属性指定使用被关联实体主键以外的字段作为关联字段
<one-to-one name="dept" class="com.elgin.hibernate.one2one.foreign.Department" property-ref="mgr"></one-to-one>未使用property-ref属性的SQL:
Hibernate: select manager0_.MGRID as MGRID1_1_1_, manager0_.MGRNAME as MGRNAME2_1_1_, department1_.DEPTID as DEPTID1_0_0_, department1_.DEPTNAME as DEPTNAME2_0_0_, department1_.MGRID as MGRID3_0_0_ from MANAGER manager0_ left outer join DEPARTMENT department1_ on manager0_.MGRID=department1_.DEPTID where manager0_.MGRID=?使用property-ref属性的SQL:
Hibernate: select manager0_.MGRID as MGRID1_1_1_, manager0_.MGRNAME as MGRNAME2_1_1_, department1_.DEPTID as DEPTID1_0_0_, department1_.DEPTNAME as DEPTNAME2_0_0_, department1_.MGRID as MGRID3_0_0_ from MANAGER manager0_ left outer join DEPARTMENT department1_ on manager0_.MGRID=department1_.MGRID where manager0_.MGRID=?
从上面2个查询时发出的sql语句可以看出,如果不使用property-ref属性,那么关联department的左外链接关联条件会错误!
测试代码:
Manager.java类:
package com.elgin.hibernate.one2one.foreign; public class Manager { private int mgrId; private String mgrName; private Department dept; public int getMgrId() { return mgrId; } public void setMgrId(int mgrId) { this.mgrId = mgrId; } public String getMgrName() { return mgrName; } public void setMgrName(String mgrName) { this.mgrName = mgrName; } public Department getDept() { return dept; } public void setDept(Department dept) { this.dept = dept; } }Department.java类
package com.elgin.hibernate.one2one.foreign; public class Department { private int deptId; private String deptname; private Manager mgr; public int getDeptId() { return deptId; } public void setDeptId(int deptId) { this.deptId = deptId; } public String getDeptname() { return deptname; } public void setDeptname(String deptname) { this.deptname = deptname; } public Manager getMgr() { return mgr; } public void setMgr(Manager mgr) { this.mgr = mgr; } }2个实体类对应的hibernate映射文件:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Generated 2015-9-25 22:25:22 by Hibernate Tools 3.4.0.CR1 --> <hibernate-mapping> <class name="com.elgin.hibernate.one2one.foreign.Manager" table="MANAGER"> <id name="mgrId" type="int"> <column name="MGRID" /> <generator class="native" /> </id> <property name="mgrName" type="java.lang.String"> <column name="MGRNAME" /> </property> <!-- 映射1对1关联关系:对应的数据表中(此处为department)如果已经有外键,当前持久化类使用one-to-one 进行映射 --> <!-- 没有外键的一端需要使用one-to-one元素,该元素的property-ref属性指定使用被关联的实体主键以外的字段作为关联字段 --> <one-to-one name="dept" class="com.elgin.hibernate.one2one.foreign.Department" property-ref="mgr"></one-to-one> </class> </hibernate-mapping>
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Generated 2015-9-25 22:25:22 by Hibernate Tools 3.4.0.CR1 --> <hibernate-mapping> <class name="com.elgin.hibernate.one2one.foreign.Department" table="DEPARTMENT"> <id name="deptId" type="int"> <column name="DEPTID" /> <generator class="native" /> </id> <property name="deptname" type="java.lang.String"> <column name="DEPTNAME" /> </property> <!-- 使用 many-to-one 的方式来映射1-1关联关系 --> <many-to-one name="mgr" class="com.elgin.hibernate.one2one.foreign.Manager"> <column name="MGRID" unique="true"></column> </many-to-one> </class> </hibernate-mapping>Junit测试类:
package com.elgin.hibernate.one2one.foreign; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; import org.junit.After; import org.junit.Before; import org.junit.Test; public class HibernateTest2 { //如此声明只为方便测试,生产环境不能这么用 private SessionFactory sessionFactory; private Session session; private Transaction transcation; @Before public void init(){ Configuration cfg=new Configuration().configure(); ServiceRegistry serviceRegistry=new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry(); sessionFactory=cfg.buildSessionFactory(serviceRegistry); session=sessionFactory.openSession(); transcation=session.beginTransaction(); } @Test public void testOne2OneForeignSave(){ Manager mgr=new Manager(); mgr.setMgrName("XXX"); Department dept=new Department(); dept.setDeptname("软件开发部"); dept.setMgr(mgr); mgr.setDept(dept); //建议先保存没有外键的一端,这样可以少发送一条update语句 session.save(mgr); session.save(dept); } @Test public void testOne2OneForeignGet(){ //1.依旧使用懒加载,默认情况下不直接查询出关联的对象,而是返回对应的代理对象,等到使用的时候再来初始化 //2.所以在session关闭的情况下仍旧会出现懒加载异常 // Department dept=(Department) session.get(Department.class, 1); // System.out.println(dept.getDeptname()); //3.查询Manager对象的左外连接条件应该是dept.manager_id=mgr.manager_id // 而不应该是dept.dept_id=mgr.manager_id //4.在查询没有外键的实体对象时使用左外连接一并查询出其关联的对象并初始化 Manager mgr=(Manager) session.get(Manager.class, 1); System.out.println(mgr.getMgrName()); } @After public void destory(){ transcation.commit(); session.close(); sessionFactory.close(); } }
基于外键的映射的1-1关联关系中,要点:
1.有外键的一端,使用many-to-one元素进行映射,并且增加unique属性,保证外键的唯一性
2.没有外键的一端,使用one-to-one元素映射,并且要指定property-ref属性