一对一的映射在对象模型中是经常见到的,主要是将对象模型转换为关系模型就必须在映射文件中进行配置,重点是<one-to-one>标签的使用,有两种方式,第一是主键关联,第二是唯一外键关联,现在先来看第一种方式。
上图的Person类和IdCard类之间是一一对应关系,一个人就只能有一个身份证,一个身份证只能对应一个人,那么身份证的标识也是人的标识,Person类的主键作为身份证IdCard类的外键。这种一对一的主键关联关系,反应到Hibernate中是怎么着的一种实现呢?像这种关系,可以有两种方式来实现。
第一种:Person中的ID不当做外键来处理,只作为Person中主键,只是人为的让Person中的ID和IdCard中的ID对应起来。在映射关系上这么处理:
IdCard.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.tgb.zhudan.IdCard" table="t_idCard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
</class>
</hibernate-mapping>
Person.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.tgb.zhudan.Person" table="t_person2">
<id name="id">
<generator class="native">
</generator>
</id>
<property name="name"/>
</class>
</hibernate-mapping>
IdCard类:
package com.tgb.zhudan;
public class IdCard {
private int id;
private String cardNo;
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;
}
}
Person类:
package com.tgb.zhudan;
public class IdCard {
private int id;
private String cardNo;
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;
}
}
hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_onetoone</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123456</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property>
<mapping resource="com/tgb/zhudan/Person.hbm.xml"/>
<mapping resource="com/tgb/zhudan/IdCard.hbm.xml"/>
</session-factory>
</hibernate-configuration>
此时在删除IdCard表的时候,能够很容易的将其删除掉。
这种方法的弊端:既然是人为控制,那么其实并不能很好的控制,不能很好的将Person的ID和IdCard中的ID对应起来,当我在IdCard中删除再添加一条,那么我这一条数据我应该怎么跟前面的Person对应起来。或者说我在Person中删除一条数据后,在添加当前一模一样的数据(注意此时ID已经改变,但是那么没有变),这样的话怎么跟IdCard中的ID怎么对应。所以说这种方式在实际应用中是不可取的。
第二种:Person中ID当做主键也当做外键来处理。映射关系如下:
主要是修改Person.hbm.xml文件。
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.tgb.zhudan.Person" table="t_person">
<id name="id">
<!-- 采用foreign生成策略,forgeign会取得关联对象的标识 -->
<generator class="foreign">
<!-- property只关联IdCard的对象 -->
<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表时会弹出这样一个提示:
提示我们不能删除,有外键约束。
总结:一句话总结一对一关联映射中的主键关联就是不需要加入多余的字段,让两个实体的主键一样。