“one-to-one(一对一映射)”对应的情景即两个实体之间的关系是一一对应,就像一个人只能有一个身份证号码一样。对应到“实体与表”之间的映射策略上来说,主要分为两种:
(1)主键关联:即让两个对象具有相同的主键值,以表明他们之间的一一对应的关系;数据库表不会有额外的字段来维护他们之间的关系,仅通过表的主键来关联。
(2)唯一外键关联:外键关联,本来是用于多对一的配置,但是如果加上唯一的限制之后,也可以用来表示一对一关联关系。
对象模型的映射原理,如图:
一对一主键关联映射:
总而言之,一对一关联映射的原理即:让两个实体的主键一致,这样就不需要加入多余的字段了。
拿上面的“Person”和“IdCard”举例说明,代码如下:
IdCard实体类:
public class IdCard {
private int id;
private String name;
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;
}
}
IdCard对应的配置文件:
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.IdCard" table="t_idCard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
</class>
</hibernate-mapping>
因为此时的一对一关联映射仍然是单向的,从Person指向IdCard,对于IdCard来说,无论是实体类,还是配置文件,正常写法。
Person实体类:
public class Person {
private int id;
private String name;
private IdCard idCard;
public IdCard getIdCard() {
return idCard;
}
public void setIdCard(IdCard idCard) {
this.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;
}
}
Person类对应的配置文件:
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.Person" table="t_person">
<id name="id">
<!-- 采用foreign生成策略,foreign会取得关联对象的标识 -->
<generator class="foreign">
<param name="property">idCard</param>
</generator>
</id>
<property name="name"/>
<!-- 表示当前主键,还是一个外键,参考了对端的主键(IdCard的主键),也就是生成外键约束语句
one-to-one指示hibernate如何加载其关联对象,默认根据主键加载,也就是拿到关系字段值,根据
对端的主键来加载关联对象
-->
<one-to-one name="idCard" constrained="true"/>
</class>
</hibernate-mapping>
由于方向性,可知在实体类中需要加入对IdCard的引用,并生成get、set方法,同时在配置文件的<class>标签当中,主键标识采用foreign生成策略,<id>标签内侧套入<generator>标签的同时,<para>标签需要说明,foreign外键到底和谁相关?其实就是在实体中引入的idCard。
最终加入<one-to-one>标签,指明name="idCard"且constrained="true".
同时在一对一主键的添加和加载过程中,Person配置文件中使用“foreign”,使得测试代码不需要session.save(idCard)即可同时将IdCard和Person一同插入库中。可见,直接session.save(person),就能够把idCard插入到表中,这是foreign的特性。
双向一对一关联映射怎么做?
有时候,一对一关联具有双向方向性,相对于单向,双向的改动量不是很大:
(1)IdCard实体类加入对Peroson类的引用:
public class IdCard {
private int id;
private String name;
private Person person;
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
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;
}
}
(2)IdCard类的配置文件
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.IdCard" table="t_idCard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
<one-to-one name="person"/>
</class>
</hibernate-mapping>
分别在实体类加入对Person的引用,同时在配置文件中加入<one-to-one>标签即可。
双向一对一唯一外键关联映射原理及具体映射
一对一唯一外键关联映射
原理:多对一映射,在外键地方加上唯一限制。采用<many-to-one>标签来映射,指定多的一端unique为true,这样就限制了多的一端的多重性为一,就是这样来映射的。
如图,限制idCard的唯一性(unique),此时,Person类中id的class类型不再为foreign,设置为native即可。
双向一对一唯一外键关联映射原理及具体映射
Person实体类:
public class Person {
private int id;
private String name;
private IdCard idCard;
public IdCard getIdCard() {
return idCard;
}
public void setIdCard(IdCard idCard) {
this.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;
}
}
Person对应的配置文件:
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.Person" table="t_person">
<id name="id">
<generator class="foreign">
<param name="property">idCard</param>
</generator>
</id>
<property name="name"/>
</class>
</hibernate-mapping>
IdCard实体类:
public class IdCard {
private int id;
private String name;
private Person person;
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
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;
}
}
IdCard对应的配置文件:
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.Person" table="t_idCard">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<one-to-one name="person" property-ref="idCard"/>
</class>
</hibernate-mapping>
一对一唯一外键关联双向采用<one-to-one>标签映射,必须指定<one-to-one>标签中的property-ref属性为关键字段的名称。