| 在 多對一 、一對多
中都是單向關聯,也就是其中一方關聯到另一方,而另一方不知道自己被關聯。 如果讓雙方都意識到另一方的存在,這就形成了雙向關聯,在多對一、一對多的例子可以改寫一下,重新設計User類別如下:
package onlyfun.caterpillar; Room類別如下:
package onlyfun.caterpillar; 如此,User實例可參考至Room實例而維持多對一關係,而Room實例記得User實例而維持一對多關係。 在映射文件方面,可以如下撰寫:
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?> 映射文件雙方都設定了cascade為save-update,所以您可以用多對一的方式來維持關聯: User user1 = new User();
user1.setName("bush"); User user2 = new User(); user2.setName("caterpillar"); Room room1 = new Room(); room1.setAddress("NTU-M8-419"); user1.setRoom(room1); user2.setRoom(room1); Session session = HibernateUtil.getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); session.save(user1); session.save(user2); tx.commit(); session.close(); 或是反過來由一對多的方式來維持關聯: User
user1 = new User();
user1.setName("bush"); User user2 = new User(); user2.setName("caterpillar"); Room room1 = new Room(); room1.setUsers(new HashSet()); room1.setAddress("NTU-M8-419"); room1.addUser(user1); room1.addUser(user2); Session session = HibernateUtil.getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); session.save(room1); tx.commit(); session.close(); 這邊有個效率議題可以探討,上面的程式片段Hibernate將使用以下的SQL進行儲存: Hibernate: insert into room
(address) values (?)
Hibernate: insert into user (name, room_id) values (?, ?) Hibernate: insert into user (name, room_id) values (?, ?) Hibernate: update user set room_id=? where id=? Hibernate: update user set room_id=? where id=? 上面的程式寫法表示關聯由Room單方面維持,而主控方也是Room,User不知道Room的room_id是多少,所以必須分別儲存Room與 User之後,再更新user的room_id。 在一對多、多對一形成雙向關聯的情況下,可以將關聯維持的控制權交給多的一方,這樣會比較有效率,理由不難理解,就像是在公司中,老闆要記住多個員工的姓 名快,還是每一個員工都記得老闆的姓名快。 所以在一對多、多對一形成雙向關聯的情況下,可以在「一」的一方設定控制權反轉,也就是當儲存「一」的一方時,將關聯維持的控制權交給「多」的一方,以上 面的例子來說,可以設定Room.hbm.xml如下:
<?xml version="1.0" encoding="utf-8"?> 由於關聯的控制權交給「多」的一方了,所以直接儲存「一」方前,「多」的一方必須意識到「一」的存在,所以程式片段必須改為如下: User
user1 = new User();
user1.setName("bush"); User user2 = new User(); user2.setName("caterpillar"); Room room1 = new Room(); room1.setUsers(new HashSet()); room1.setAddress("NTU-M8-419"); room1.addUser(user1); room1.addUser(user2); // 多方必須意識到單方的存在 user1.setRoom(room1); user2.setRoom(room1); Session session = HibernateUtil.getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); session.save(room1); tx.commit(); session.close(); 上面的程式片段Hibernate將使用以下的SQL: Hibernate: insert into room
(address) values (?)
Hibernate: insert into user (name, room_id) values (?, ?) Hibernate: insert into user (name, room_id) values (?, ?) 如果控制權交給另一方了,而另一方沒有意識到對方的存在的話會如何?試著將上面的程式片段中user1.setRoom(room1);與 user2.setRoom(room1);移去,執行之後,您會發現資料庫中room_id會出現null值,這種結果就好比在 多對一 中,您沒有分配給User一個Room,理所當然的,room_id會出現null。 |