本篇博客介绍一下hibernate中一对一关联映射的配置和使用,一对一关联映射分为单向一对一关系和双向一对一关系,单向一对一分为唯一外键关联映射和主键关联映射,双向一对一分为双向主键关联和双向外键关联,下面介绍这四种关联映射。
一、单向一对一关系映射
(1)唯一外键关联映射
唯一外键是表中每一行外键唯一对应着另一个表中的主键,也就是说另一个表的主键唯一作为另一个表的外键,关系如下所示:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2QvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2Lc1zaq1UNBpXT4N2MkZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39TN5QDOykDMxEDOwEDM3EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
一个人对应着一个身份证,省份证表的id是人实体表中的外键,这种实现类似乎多对一映射,一个表的主键标识列是另一个表的外键,使用<many-to-one>标签,但是这里应该采用的是唯一对应,此时应该设置它的属性来做唯一标识,需要在<many-to-one>标签中加上属性unique,指定多的一端的unique值为true。所以需要在person的映射文件中设置一个<many-to-one name="idCard" unique="true">.对应的Person.hbm.xml代码为:
<hibernate-mapping>
<class name="com.hibernate.Person" table="t_person">
<id name="id" type="int">
<generator class="native"/>
</id>
<property name="name"></property>
<many-to-one name="idCard" unique="true"></many-to-one>
</class>
</hibernate-mapping>
(2)主键关联映射
一对一关联映射还存在一种情况就是一个表的主键同时也是另外一个表的外键,并且是唯一的,就是说一个表的字段同时是主键和外键,关系如下所示:
t_person里面的主键同时对应t_idCard里面的外键,两个表的id是一一对应的。使用<one-to-one>的关系,<param name="property">idCard</param>指的是在Person.java中有一个idCard的属性,该属性是Person对象的一个关联对象,所以需要注册到foreign中,取得关联对象的标识。另外在<one-to-one>标签中添加了一个属性constrained="true",指示了Person对象的主键同时又是一个外键,需要注意建立Person类时需要添加idCard属性。
person.hbm.xml代码:
<hibernate-mapping>
<class name="com.hibernate.Person" table="t_person">
<id name="id">
<!-- 采用foreign生成策略,forgeign会取得关联对象的标识 -->
<generator class="foreign">
<!-- property只关联对象 -->
<param name="property">idCard</param>
</generator>
</id>
<property name="name"/>
<!--
one-to-one指示hibernate如何加载其关联对象,默认根据主键加载
也就是拿到关系字段值,根据对端的主键来加载关联对象
constrained="true表示,当前主键(person的主键)还是一个外键
参照了对端的主键(IdCard的主键),也就是会生成外键约束语句
-->
<one-to-one name="idCard" constrained="true"/>
</class>
</hibernate-mapping>
IdCard.hbm.xml代码如下:
<hibernate-mapping>
<class name="com.hibernate.IdCard" table="t_idCard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
<one-to-one name="person"/>
</class>
</hibernate-mapping>
二、双向一对一关系映射
(1)双向主键关联
双向主键关联其实是单向一对一关联映射的一种特殊情况,不同的是要在关联对象的两端的配置文件中都要进行<one-to-one>的配置。一个人对应着一个唯一的身份证,一个身份证也唯一映射着一个人,这就是一种双向的关联关系,person的主键同样也是IDcard的主键,是主键的同时为外键,关系如下所示:
Person.hbm.xml映射文件,该文件中主键生成策略没有特殊的要求,因为它和IdCard类相互制约的关系,它的主键和外键都是IdCard的主键,另外因为是一对一关系所以要在映射文件中添加<one-to-one>标签。
<hibernate-mapping>
<class name="com.src.hibernate.Person" table="t_Person">
<id name="id" type="int" column="personId">
<generator class="native"></generator>
</id>
<property name="name" type="string" column="personName"></property>
<!--
one-to-one标签指示Hibernate如何加载其关联对象,默认根据主键加载,也就是拿到关系字段值,根据对端的主键来加载关联对象
-->
<one-to-one name="idcard"></one-to-one>
</class>
</hibernate-mapping>
IdCard.hbm.xml映射文件,在映射文件中添加外键属性person,并添加对应的<one-to-one>标签,目的是强制约束person类来实现一对一的映射关系,最后在映射中将constrained属性设为true,保证强制约束关系。
<hibernate-mapping>
<class name="com.src.hibernate.IdCard" table="t_idCard">
<id name="id" type="int" column="personId">
<generator class="foreign">
<param name="property">person</param>
</generator>
</id>
<property name="cardNo" type="string" column="cardno"></property>
<one-to-one name="person" constrained="true"></one-to-one>
</class>
</hibernate-mapping>
idCard.java类, IdCard类和Person类之间有一对一的关联关系所以要在IdCard类中添加对应的Person属性,这是为了能在映射文件中的外键中添加对应的属性,设置对应的外键关联类。
public class IdCard {
private int id;
private String cardNo;
private Person person;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCardNo() {
return cardNo;
}
public void setCardNo(String cardNo) {
this.cardNo = cardNo;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
Person.java类,在该类中除了添加基本的属性外还要添加对应的IdCard类作为属性,因为它们之间是一对一的双向关联关系,所以在Person类中同样要添加IdCard类,相同的道理IdCard类中同样添加了Person类属性。
public class Person {
private int id;
private String name;
private IdCard idCard;
public int getId() {
return id;
}
public void setId(int 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;
}
}
(2)双向一对一关联映射
双向一对一关联映射可以理解为外键关联的一种特殊情况,只不过是一种双向的对应关系。任何身份证是一对一的关系,person表中有idCard表的主键,也就是说通过person可以获取到IDCard,通过idCard也可以获取到person,并且他们的关系是双向的,它们的关系如下图所示:
对象模型:
关系模型:
idCard.hbm.xml映射文件,idCard表不是映射的主表,所以在做一对一的映射时需要使用的是<one-to-one>标签来配置,并且需要制定person关系模型中的外键属性,idCard映射文件如下:
<hibernate-mapping>
<class name="com.src.hibernate.IdCard" table="t_idCard">
<id name="id" type="int">
<generator class="native" />
</id>
<property name="cardNo" type="java.lang.String">
<column name="CARDNO" />
</property>
<one-to-one name="person" property-ref="idCard"></one-to-one>
</class>
</hibernate-mapping>
Person.hbm.xml映射文件,person表是映射的主表,需要在该表中添加一个外键属性列来标示idCard表,所以这里需要使用<many-to-one>标签,在person对象中生成相应的外键,并且还要使用unique表示属性唯一。
<hibernate-mapping>
<class name="com.src.hibernate.Person" table="t_person">
<id name="id" type="int" column="personId">
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<many-to-one name="idCard" column="idCardNo" unique="true" not-null="true"></many-to-one>
</class>
</hibernate-mapping>
小结:
从上面的单向和双向映射关系以及分别对应的主键和外键两种映射,可以发现外键映射只需要在存在外键的表中使用
<many-to-one>标签,因为唯一所以要添加unique属性。
<one-to-one>标签表明了一种一对一的关系,只是表明一个对象如何加载另一个对象并不在关系模型中添加新列。
主键使用<one-to-one>不会生成属性列,必须对表的主键采用foreign的主键生成策略,必须表明外键对象。
外键映射需要采用<many-to-one>生成外键列。