一對一(唯一外鍵關聯)


現在考慮每一個User配給一間Room,形成一對一,user表格透過room_id作為外鍵參考至room:

一對一


在表格建立方面,使用 多對一 中的表格建立語句就可以了:
    create table room (
        id bigint not null auto_increment,
        address varchar(255),
        primary key (id)
    )

    create table user (
        id bigint not null auto_increment,
        name varchar(255),
        room_id bigint unique,
        primary key (id)
    )


物件方面,User的實例會參考至Room實例,而Room實例也參考至User實例:
  • User.java
package onlyfun.caterpillar;

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

public User() {}

public Long getId() {
return id;
}

public void setId(Long 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 Long id;
private String address;
private User user;

public Room() {}

public Long getId() {
return id;
}

public void setId(Long 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">
<generator class="native"/>
</id>

<property name="name" column="name"/>

<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" />

<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 = HibernateUti.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
 
session.save(user1);
session.save(user2);
       
tx.commit();
session.close();

在查詢Room時,User也會一載入,例如:
Session session = HibernateUtil.getSessionFactory().openSession();
Room room = (Room) session.load(Room.class, new Long(23));
System.out.println(room.getUser().getName());
session.close();

上面的查詢程式,Hibernate將使用以下的SQL:
Hibernate:
    select
        room0_.id as id1_1_,
        room0_.address as address1_1_,
        user1_.id as id0_0_,
        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=?