单向或双向: 同一个类型的映射单向或双向对应的数据库的表结构是一样的,受影响的是在程序中进行增删改查时体现出来的。
下面通过最常见的1:1的单向和双向来举例说明。1:1类型的可以通过主键进行关联也可以通过外键进行关联,这里我们用比较常见的外键关联。
场景说明:一个人有且只有一个身份证号
单向:
一、对象关系:
按照以上设计的对象关系在程序中建立对应类——
1、被依赖的IdCard类:
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;
}
}
2、依赖的Person类:持有被依赖对象IdCard的 引用
public class Person {
private int id;
private String name;
private IdCard 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;
}
}
二、数据设计
面向对象思想设计的类图我们很熟悉,落实后看一下对应的数据库的设计图如下:
在t_person表中持有t_idCard表中的主键作为自身的外键。这种设计也是我们平时设计数据库时最常用的形式。
现在O端和R都有了,剩下的就是通过配置文件将Object和Relationship进行Mapping。首先是被依赖的IdCard,只需要映射自身的主键id和身份证号cardNo。
<?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.bjpowernode.hibernate.IdCard" table="t_idCard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
</class>
</hibernate-mapping>
其次是进行依赖的Person,需要映射自身主键Id,属性name以及引入的IdCard
<?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.bjpowernode.hibernate.Person" table="t_person">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<many-to-one name="idCard" unique="true"/>
</class>
</hibernate-mapping>
看到配置文件就该有疑问了为什么不是使用的one-to-one而是使用的many-to-one,因为在Person端添加了IdCard的主键作为外键从某种角度来说 一对一外键映射是一种特殊的 多对一,添加外键唯一性的约束即可。配置完毕之后可以用实例进行测试。
查询:
public void testLoad1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Person person = (Person)session.load(Person.class, 2);
System.out.println("person.name=" + person.getName());
System.out.println("person.cardNo=" + person.getIdCard().getCardNo());
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
因为在Person添加了IdCard的引用,并且在Person的映射文件中添加了many-to-one的映射,所以在加载Person时可以通过外键将IdCard查出得到关联的信息。
双向:
一、对象关系:在IdCard中也添加了对Person的引用,Person类同单向关联一样保存有对IdCard的引用。
按照以上设计的对象关系在程序中建立对应类——
1、Person类保持不变,IdCard类添加对Person的引用:
public class IdCard {
private int id;
private String cardNo;
private Person 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的映射文件保持不变,由于IdCard添加了对Person的引用所以配置文件需要修改
<?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.bjpowernode.hibernate.IdCard" table="t_idCard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
<one-to-one name="person" property-ref="idCard"/> </class>
</hibernate-mapping>
添加了one-to-one的配置,需要注意:添加属性 property-ref="idCard" 的值“idCard”为person的映射文件中many-to-one 的name的值。因为在级联加载时,IdCard会用主键和Person中的该外键对比。 双向关联配置完毕,通过代码实例进行 查询测试 发现不仅仅可以在查询Person时关联取到IdCard的值,在查询IdCard时也可以关联的取到Person的值。
小结:
1、外键唯一的一对一单向映射是一种特殊的多对一映射,需要添加外键唯一配置。
2、单向关联和双向关联的数据库是一样的
3、单向只能从保有引用的一端查看到被引用一端,双向的则都可以。
hibernate对JDBC进行封装后基本的增删改查方法不再需要我们写sql语句,通过映射文件的配置就可以达到连接查询的效果,hibernate的好处不仅仅是这个,映射文件中的很多属性还需要进一步的使用了解。