1. 程式人生 > >一口一口吃掉Hibernate(四)——多對一單向關聯對映

一口一口吃掉Hibernate(四)——多對一單向關聯對映

【轉自 http://blog.csdn.net/xiaoxian8023 】 https://blog.csdn.net/xiaoxian8023/article/details/12249889

可能有人會對這2篇部落格的題目有點混淆不清,跟日常說的關係有點不同。我們日常說的比如父子關係,夫妻關係都是說的雙向關係,而現在討論的則是單向關係,所以也就有了多對一和一對多的說法。

      二者的關係其實很簡單,只是角度不同而已。比如說學生和班級的關係。如果從學生角度來看,是多對一的關係。而從班級角度來看,則是一對多的關係。說法很簡單,但是在物件和關係的建立卻是不一樣的。

      先看一下一對多的類圖(貌似好多人的聚合關係都畫錯了):

     Hibernate對於一對多的關係的處理,是通過操作Class端,間接操作或者自動操作Student端。比如新增,我直接新增Class端的資料,多個Student就會被新增自動新增進去。也可以通過這個Class獲取到所有對應的學生資訊。跟著我來配置一下吧:

      首先定義實體類【Class】【Student】

  1. package com.bjpowernode.hibernate;
  2. import java.util.Set;
  3. /**
  4. * 班級類
  5. * @author Longxuan
  6. *
  7. */
  8. public class Class {
  9. private int id;
  10. private String name;
  11. private Set<Student> students;
  12. public Set<Student> getStudents() {
  13. return students;
  14. }
  15. public void setStudents(Set<Student> students)
    {
  16. this.students = students;
  17. }
  18. public int getId() {
  19. return id;
  20. }
  21. public void setId(int id) {
  22. this.id = id;
  23. }
  24. public String getName() {
  25. return name;
  26. }
  27. public void setName(String name) {
  28. this.name = name;
  29. }
  30. }
  31. package com.bjpowernode.hibernate;
  32. /**
  33. * 學生類
  34. * @author Longxuan
  35. *
  36. */
  37. public class Student {
  38. private
    int id;
  39. private String name;
  40. public int getId() {
  41. return id;
  42. }
  43. public void setId(int id) {
  44. this.id = id;
  45. }
  46. public String getName() {
  47. return name;
  48. }
  49. public void setName(String name) {
  50. this.name = name;
  51. }
  52. }
      hibernate.cfg.xml配置檔案和hibernate.properties配置檔案跟上篇博文中的一致,只是資料庫名不同而已。自行修改或者不修改都可。

      Hibernate提供了one-to-many來簡化一對多的對映關係。不用我們自己再去實現,只需要在對映檔案中進行配置即可:

  1. <?xml version="1.0"?>
  2. <!DOCTYPE hibernate-mapping PUBLIC
  3. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  4. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  5. <hibernate-mapping package="com.bjpowernode.hibernate">
  6. <class name="Student" table="t_student">
  7. <id name="id">
  8. <generator class="native"/>
  9. </id>
  10. <property name="name"/>
  11. </class>
  12. <class name="Class" table="t_class">
  13. <id name="id">
  14. <generator class="native"/>
  15. </id>
  16. <property name="name"/>
  17. <!-- 設定Set,用於關聯多個學生 -->
  18. <set name="students">
  19. <!-- 在t_student表中建立外來鍵classid,與本表的id對應 -->
  20. <key column="classid"></key>
  21. <one-to-many class="Student"></one-to-many>
  22. </set>
  23. </class>
  24. </hibernate-mapping>
      配置了one-to-many會自動在t_student表中建立外來鍵classid,與t_class的id對映。

      測試類【One2ManyTest

  1. package com.bjpowernode.hibernate;
  2. import java.util.HashSet;
  3. import java.util.Iterator;
  4. import java.util.Set;
  5. import junit.framework.TestCase;
  6. import org.hibernate.Session;
  7. import org.hibernate.Transaction;
  8. public class One2ManyTest extends TestCase {
  9. public void testSave2() {
  10. Session session = null;
  11. try {
  12. session = HibernateUtils.getSession();
  13. session.beginTransaction();
  14. Student student1 = new Student();
  15. student1.setName("張三");
  16. //必須先將student1轉化為Persistent狀態,否則會拋TransientObjectException
  17. session.save(student1);
  18. Student student2 = new Student();
  19. student2.setName("李四");
  20. //必須先將student1轉化為Persistent狀態,否則會拋TransientObjectException
  21. session.save(student2);
  22. Class classes = new Class();
  23. classes.setName("提高班");
  24. Set<Student> students = new HashSet<Student> ();
  25. students.add(student1);
  26. students.add(student2);
  27. classes.setStudents(students);
  28. //可以成功儲存資料。
  29. //先新增資料,將關係欄位設定為null,再用update語句來更新關係欄位
  30. //但是會發出多餘的update語句來維持關係。
  31. session.save(classes);
  32. session.getTransaction().commit();
  33. }catch(Exception e) {
  34. e.printStackTrace();
  35. session.getTransaction().rollback();
  36. }finally {
  37. HibernateUtils.closeSession(session);
  38. }
  39. }
      結果圖:

      執行測試前: ,執行測試後:

      雖然最後的結果跟多對一一樣,但是根據sql語句,就可以看出,一對多是先新增student,classid為null,等添加了class以後,再執行update語句,把classid更新上去。這樣同時可能會暴露一個問題:如果student的classid設定了not-null="true",則會拋PropertyValueException異常。所以不太推薦使用一對多。

      通過上面的例子,我們可以看出,其實一對多關聯對映和多對一關聯對映對映原理是一致的,都是在多的一端加入一個外來鍵,指向一的一端。

      它們的區別在於維護的關係不同:

    • 多對一維護的關係是:多指向一的關係,有了此關係,在載入多的時候可以將一載入上來
    • 一對多維護的關係是:一指向多的關係,有了此關係,在載入一的時候可以將多載入上來

      在一的一端維護關係存在缺陷:

    • 因為多的一端Student不知道Class的存在(也就是Student沒有維護與Class的關係)所以在儲存Student的時候關係欄位classid是為null的,如果將該關係欄位設定為非空,則將無法儲存資料
    • 另外因為Student不維護關係,而Class維護關係,Class就會發出多餘的update語句,保證Class和Student有關係,這樣載入Class的時候才可以把該Class對應的學生載入上來