一对一关系映射即为关系双方都含有对方一个引用,其实在生活中一对一关系也很常见,比如人和身份证,学生和学号等,都是一对一的关系映射,一对一映射分为单向的和双向的,没种关系映射又可以分为主键关联映射,唯一外键关联映射。
一:主键关联映射
一般一对一主键关联映射通过foreign主键生成器使用另外一个相关联的对象的标识符。通常和<one-to-one>联合起来使用。一对一主键关联映射原理:让两个实体的主键一样,这样就不需要加入多余的字段。此种关联映射有一定的缺点:单向一对一主键关联实际上限制很多,因为你只有IdCard插入了那才能有这个Person.我们看一下具体示例:
根据上面的关系类图,我们再来看一下实体类的定义
实体IdCard.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | package com.lpq.domain; import java.io.Serializable; import java.util.Date; public class IdCard implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private Integer id; private Date validateDte; private Person person; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Date getValidateDte() { return validateDte; } public void setValidateDte(Date validateDte) { this.validateDte = validateDte; } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } } |
实体:Person.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package com.lpq.domain; import java.io.Serializable; public class Person implements Serializable{ private static final long serialVersionUID = 1L; private Integer id; private String name; private IdCard idCard; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public IdCard getIdCard() { return idCard; } public void setIdCard(IdCard idCard) { this.idCard = idCard; } } |
IdCard的配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.lpq.domain"> <class name="IdCard" table="idCard"> <id name="id" type="java.lang.Integer"> <column name="id" /> <generator class="foreign"> <param name="property">person</param> </generator> </id> <property name="validateDte" type="java.util.Date"> <column name="validateDte"/> </property> <one-to-one name="person" constrained="true"></one-to-one> </class> </hibernate-mapping> |
person的配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.lpq.domain"> <class name="Person" table="person"> <id name="id" type="java.lang.Integer"> <column name="id" /> <generator class="assigned" /> </id> <property name="name" type="java.lang.String"> <column name="name" length="128"/> </property> <one-to-one name="idCard"></one-to-one> </class> </hibernate-mapping> |
注:one-to-one标签告诉hibernate根据主键加载引用对象 , 把person中的主键拿到idCard表中进行查找,然后把查到的信息加载到引用对象中采用一对一主键约束,那么必须设置constrained属性,表示当前主键作为外键参照了该属性在一对一主键关联映射中默认问级联属性。
表明该类对应的表对应的数据库表,和被关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。这个选项影响save()和delete()在级联执行时的先后顺序以及决定该关联能否被委托。
配置完了以后我们来看一下具体操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | package com.lpq.view; import java.util.Date; import org.hibernate.Session; import org.hibernate.Transaction; import com.lpq.domain.IdCard; import com.lpq.domain.Person; import com.lpq.util.HibernateUtil; public class TestMain { public static void main(String[] args) { Session s = null; Transaction ts = null; try { s = HibernateUtil.getCurrentSession(); ts = s.beginTransaction(); Person p1 = new Person(); p1.setId(1235); p1.setName("lpq"); IdCard idCard = new IdCard(); idCard.setValidateDte(new Date()); idCard.setPerson(p1);//表示idCard是属于p1这个对象的 s.save(p1); s.save(idCard); ts.commit(); } catch (Exception e) { e.printStackTrace(); if(ts!=null){ ts.rollback(); } }finally{ if(s!=null&&s.isOpen()){ s.close(); } } } } |
通过执行查询,我们可以发现,hibernate的一对一默认执行的检索方式是外连接检索方式,如果我们不想用外连接检索方式,我们可以设置一下one-to-one的fetch属性,他有两个值,一个是select,一个是jion。我想大家通过字面也能猜出他们所对应的检索方式。
Hibernate一对一中也可以设置延迟加载,一对一默认使用的是立即加载,如果需要使用延迟加载,那么需要在one-to-one元素中将constrained属性设为true,并且将待加载的一方的class元素中的lazy属性设为true(或者不去设置,因为该属性默认值就是true)。一对一加载时默认使用左外连接,可以通过修改fetch属性为select修改成每次发送一条select语句的形式。
唯一外键关联映射:其实它是一对多的特殊情况,它基本和一对多是完全相同的,只不过需要配置一个属性而已。其本质上是一对多的蜕化形式。在many-to-one元素中增加unique=”true”属性就变成了一对一。
二、一对唯一外键关联映射——单向
1.一对唯一外键关联映射是多对一关联映射的特例,可以采用<many-to-one>标签,指定多的一端的unique=true,这样就限 制了多的一端的多重性为一,通过这种手段映射一对一唯一外键关联
2.领域模型图:
3.配置
Person.hbm.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.lpq.domain"> <class name="Person" table="person"> <id name="id" type="java.lang.Integer"> <column name="id" /> <generator class="assigned" /> </id> <property name="name" type="java.lang.String"> <column name="name" length="128"/> </property> <one-to-one name="idCard"></one-to-one> </class> </hibernate-mapping> |
IDCard.hbm.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.lpq.domain"> <class name="IdCard" table="idCard"> <!-- 基于外键的one-to-one --> <id name="id" type="java.lang.Integer"> <generator class="assigned"></generator> </id> <property name="validateDte" type="java.util.Date"> <column name="validateDte"/> </property> <many-to-one name="person" unique="true"></many-to-one> </class> </hibernate-mapping> |
除非注明,Coder文章均为原创,转载请以链接形式标明本文地址