ITEEDU

Hibernate Gossip: 一对一(唯一外键关联)

现在考虑每一个User配给一间Room,形成一对一,user表格透过room_id作为外键参考至room:

一对一

在表格建立方面,使用 多对一 中的表格建立语句就可以了:
CREATE TABLE user (
    id INT(11) NOT NULL auto_increment PRIMARY KEY,
    name VARCHAR(100) NOT NULL default '',
    room_id INT(11)
);

CREATE TABLE room (
    id INT(11) NOT NULL auto_increment PRIMARY KEY,
    address VARCHAR(100) NOT NULL default ''
);
对象方面,User的实例会参考至Room实例,而Room实例也参考至User实例:
User.java
package onlyfun.caterpillar;

public class User {
private Integer id;
private String name;
private Room room;

public User() {
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Room getRoom() {
return room;
}

public void setRoom(Room room) {
this.room = room;
}
}
Room.java
package onlyfun.caterpillar; 

public class Room {
private Integer id;
private String address;
private User user;

public Room() {
}

public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}

public User getUser() {
return user;
}

public void setUser(User user) {
this.user = user;
}
}

使用外键来完成一对一,其实就是限制多对一关系中,「多」的一方只能有一个参考至「一」的一方,也就是多对一关系的一个特例,这可以在映射文件中使用<many-to-one>卷标时,加上"unique"属性来设定,例如:
User.hbm.xml
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<class name="onlyfun.caterpillar.User" table="user">
<id name="id" column="id" type="java.lang.Integer">
<generator class="native"/>
</id>

<property name="name" column="name" type="java.lang.String"/>

<many-to-one name="room"
column="room_id"
class="onlyfun.caterpillar.Room"
cascade="all"
outer-join="true"
unique="true"/>
</class>

</hibernate-mapping>
到这边为止,单向一对一的映像已经完成,如果要再完成双向一对一的关系,则可以在Room.hbm.xml中使用<one-to-one>标签来定义:
Room.hbm.xml
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<class name="onlyfun.caterpillar.Room" table="room">
<id name="id" column="id">
<generator class="native"/>
</id>

<property name="address"
column="address"
type="java.lang.String"/>

<one-to-one name="user"
class="onlyfun.caterpillar.User"
property-ref="room"/>
</class>

</hibernate-mapping>
在<one-to-one>中,property-ref告诉Hibernate,查询出user并将其参考至room。

一个储存的例子如下:
User user1 = new User();
user1.setName("bush"); 
Room room1 = new Room(); 
room1.setAddress("NTU-M8-419");
user1.setRoom(room1);
        
User user2 = new User(); 
user2.setName("caterpillar"); 
Room room2 = new Room(); 
room2.setAddress("NTU-M8-418");
user2.setRoom(room2);
        
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
 
session.save(user1);
session.save(user2);
        
tx.commit();
session.close();
在查询Room时,User也会一加载,例如:
Session session = sessionFactory.openSession();
Room room = (Room) session.load(Room.class, new Integer(23));
System.out.println(room.getUser().getName());
session.close(); 
上面的查询程序,Hibernate将使用以下的SQL:
Hibernate:
select room0_.id as id1_, room0_.address as address1_1_, user1_.id as
id0_, user1_.name as name0_0_, user1_.room_id as room3_0_0_ from room
room0_ left outer join user user1_ on room0_.id=user1_.room_id where
room0_.id=?