接續 多對一 的內容,User對Room是多對一的關係,反過來Room對User就是一對多的關係,若要由Room來維持User的參考,則您可以如下設計:
- Room.java
package onlyfun.caterpillar;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
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.OneToMany;
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;
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="ROOM_ID_FK")
private Set<User> users;
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
public void addUser(User user) {
users.add(user);
}
public void removeUser(User user) {
users.remove(user);
}
// 以下為 Getter、Setter
....
}
在這邊使用Set來維持對多個User實例的參考,而您的User可以如下設計:
- User.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_USER")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="USER_ID")
private Long id;
private String name;
private Long age;
// 以下為 Getter、Setter
....
}
一個儲存的例子如下所示,由於現在是由Room來維持對User的參考,所以直接儲存Room實例,User實例也會一併儲存:
User user1 = new User();
user1.setName("caterpillar");
user1.setAge(new Long(30));
User user2 = new User();
user2.setName("Justin");
user2.setAge(new Long(35));
Room room = new Room();
room.setUsers(new HashSet<User>());
room.setAddress("NTU-M8-419");
room.addUser(user1);
room.addUser(user2);
EntityManager entityManager =
JPAUtil.getEntityManagerFactory().createEntityManager();
EntityTransaction etx = entityManager.getTransaction();
etx.begin();
entityManager.persist(room);
etx.commit();
entityManager.close();
這個時候,有個效能上的議題可以探討,請參考 雙向關聯。
在查詢時,要注意的是,@OneToMany預設的Fetch模式是FetchType.LAZY,若您直接以下面的程式打算顯示User資訊:
EntityManager entityManager =
JPAUtil.getEntityManagerFactory().createEntityManager();
EntityTransaction etx = entityManager.getTransaction();
etx.begin();
room = entityManager.find(Room.class, new Long(1));
etx.commit();
entityManager.close();
System.out.println(room.getUsers());
FetchType.LAZY時,除非真正要使用到該屬性的值,否則不會真正將資料從表格中載入物件,所以上例中,由於EntityManager已經關閉,而此時若要再載入User,就會發生例外錯誤,解決的方式之一是在EntityManager關閉前取得資料。
EntityManager entityManager =
JPAUtil.getEntityManagerFactory().createEntityManager();
EntityTransaction etx = entityManager.getTransaction();
etx.begin();
room = entityManager.find(Room.class, new Long(1));
etx.commit();
System.out.println(room.getUsers());
entityManager.close();
或者是在@OneToMany上指定fetch屬性為FetchType.EAGER,表示一併載入所有屬性所對應的資料:
@OneToMany(cascade=CascadeType.ALL, mappedBy="room", fetch=FetchType.EAGER)
private Set<User> users;
關於Fetch模式的說明,還可以參考 CascadeType 與 FetchType。