多對一


若多個使用者可共住一個房間,則使用者與房間的關係就是多對一的關係。



您可以使用@ManyToOne於User類別的Room屬性上標示多對一關係,例如:
  • User.java
package onlyfun.caterpillar;

import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name="T_USER")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="USER_ID")
private Long id;
private String name;
private Long age;

@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="ROOM_ID_FK")
private Room room;
// 以下為 Getter、Setter
....
}

而Room類別可以撰寫如下:
  • Room.java
package onlyfun.caterpillar;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="T_ROOM")
public class Room implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="ROOM_ID")
private Long id;
private String address;

// 以下為 Getter、Setter
....
}

在這樣的設定下,是由User維持對Room的參考來維持多對一的關係,Room並沒有意識到User的存在,而您在儲存時,由於設定了CascadeType.ALL,所以直接儲存User實例時,所參考的Room實例也會一併被儲存,例如一個範例如下所示:
        Room room = new Room();
        room.setAddress("NTU-M8-419");
       
        User user1 = new User();
        user1.setName("caterpillar");
        user1.setAge(new Long(30));
        user1.setRoom(room);

        User user2 = new User();
        user2.setName("Justin");
        user2.setAge(new Long(35));
        user2.setRoom(room);

        EntityManager entityManager =
                JPAUtil.getEntityManagerFactory().createEntityManager();
        EntityTransaction etx = entityManager.getTransaction();
        etx.begin();
        entityManager.persist(user1);
        entityManager.persist(user2);
        etx.commit();
        entityManager.close();

此時會先儲存Room實例,取得ROOM_ID之後,再儲存User實例,並將ROOM_ID_FK設為與ROOM_ID相同,此時表格內容如下所示:



而如果您使用以下的方式查詢:
User user = entityManager.find(User.class, new Long(1));

在使用Hibernate作為JPA的實作時,會產生以下的SQL語句:
Hibernate:
    select
        user0_.USER_ID as USER1_0_1_,
        user0_.age as age0_1_,
        user0_.name as name0_1_,
        user0_.ROOM_ID_FK as ROOM4_0_1_,
        room1_.ROOM_ID as ROOM1_1_0_,
        room1_.address as address1_0_
    from
        T_USER user0_
    left outer join
        T_ROOM room1_
            on user0_.ROOM_ID_FK=room1_.ROOM_ID
    where
        user0_.USER_ID=?