一、关系 & 映射
我们先将关系映射,我们拆成“关系”和“映射”两部分。
关系:不陌生,在“程序员”的概念里最基本的就是表表之间的关系,类类之间的关系,这里要说的关系就这两种。一个系统中的任何一个实体都不是独立的,这就是我们类图中各个类之间的相互引用。类图间的关系表现在数据库中,就是表之间的的外键约束。这些关系有:一对一,一对多,多对一,多对多,继承。 关系的使用,就涉及到方向的问题,所以,以上几种关系都有方向存在。
回想之前的设计,step1:类的设计是一部分,形成OOM,拿着oom来生成我们的“代码”;
step2:数据库的设计是另一部分,形成PDM,用PDM形成database。
当然都知道利用powerdesigner 等工具,在oom和pdm之间,是可以相互转换的,编程的工作量是大大减轻了,即便这样,还是有更先进的思想,来解放我们的劳动力,在哪?就是hibernate。
映射:将实体映射到数据库,基于实体间的关系,这里的一个“映射”包含了N多种情况,hibernate是怎么节省工作量的呢?hibernate将之前的两步,做成了“一步到位”。从代码开始设计对象,通过“xml”映射到数据库。hibernate使编程更专注于“对象”的设计。那么系统中“对象”键的关系是怎么“映射”到数据库中呢?这其中的原理最重要的就是:Hibernate 靠什么来区分对象间的不同关系?hibernate定义了一套“关系”映射的约定,来区分对象之间的不同关系。这样我们以前需要手动去维护的数据表外键约束,就被hibernate给代劳了。
接下来就看看hibernate中的这套约定。
二、关系规范实现
(这篇博客说一对一的关系映射的实现)
一对一
有两种实现方式,主键关联映射,唯一外键关联映射。约定:one-to-one
实现方式:让两个实体的主键一样,这样就不需要加入多余的字段了
单向关联Person----->IdCard
person中存在IdCard的引用,反之没有,对应的,IdCard.hbm.xml 文件不会发生变化。需要在person.hbm.xml中加入维护关系的约定内容。
关系图如下;
实体类实现如下:
<span style="font-family:KaiTi_GB2312;font-size:18px;"> 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;
}
}
</span>
person端的hbm.xml编写:
<span style="font-family:KaiTi_GB2312;font-size:18px;"> <class name="com.bjpowernode.hibernate.Person" table="t_person">
<id name="id">
<!-- 采用foreign生成策略,forgeign会取得关联对象的标识 -->
<generator <strong>class="foreign"</strong>>
<!-- property只关联对象 -->
<param name="property">idCard</param>
</generator>
</id>
<property name="name"/>
<strong><one-to-one name="idCard" constrained="true"/></strong>
<!-- one-to-one指示hibernate如何加载其关联对象,默认根据主键加载也就是拿到关系字段值,根据对端的主键来加载关联对象
constrained="true表示,当前主键(person的主键)还是一个外键参照了对端的主键(IdCard的主键),也就是会生成外键约束语句 -->
</class>
</span>
双向关联
在IdCard中加入Person的引用;
在IdCard一段也加入维护关系的约定内容,<one-to-one name="person" />
IdCard配置文件如下:
<span style="font-family:KaiTi_GB2312;font-size:18px;"> <hibernate-mapping>
<class name="com.bjpowernode.hibernate.IdCard" table="t_idCard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
<strong><one-to-one name="person"/></strong>
</class>
</hibernate-mapping>
</span>
2、唯一外键关联
引入对端实体的主键做外键约束,来实现,实体都有自己各自的主键,不共享主键。
约定:<many-to-one> & <one-to-one>
一对一唯一外键关联映射其实是多对一的特例,采用<many-to-one>标签来映射,指定多的一端unique为true,这样就限制了多的一端的多重性为一,就是这样来映射的。
数据表图:
person的映射文件如下:
<span style="font-family:KaiTi_GB2312;font-size:18px;"><hibernate-mapping>
<class name="com.bjpowernode.hibernate.Person" table="t_person">
<id name="id">
<generator class="native"/>
</id>
property name="name"/>
<strong><many-to-one name="idCard" unique="true"/></strong>
</class>
</hibernate-mapping></span>
双向关联实现——one-to-one
这里和一对一主键关联的一点小区别是:唯一外键关联在双向关联的时候,没有外键的一方是一对一的关系,有外键的一方是一对多的关系,所以IdCard使用的是one-to-one
IdCard 映射文件如下:
<span style="font-family:KaiTi_GB2312;font-size:18px;"><hibernate-mapping>
<class name="com.bjpowernode.hibernate.IdCard" table="t_idCard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
<strong><one-to-one name="person" property-ref="idCard"/></strong>
</class>
</hibernate-mapping>
</span>
两种方式的对比
一对一主键关联:共用一个主键,耦合性太大,双方关系发生变化,数据库表就得重新建,不建议使用。
唯一外键关联:增加一个字段,来维护关联关系,灵活性增加。如双发关系由一对一向一对多改变的情况下,只需将限制外键的unique设置为false即可实现,建议使用。
下篇博客是一对多的实现