1. 程式人生 > >一口一口吃掉Hibernate(八)——Hibernate中inverse的用法

一口一口吃掉Hibernate(八)——Hibernate中inverse的用法

設置 XML 示例代碼 映射文件 代碼 參加 property 如果 people

一、Inverse是hibernate雙向關系中的基本概念。inverse的真正作用就是指定由哪一方來維護之間的關聯關系。當一方中指定了“inverse=false”(默認),那麽那一方就有責任負責之間的關聯關系,說白了就是hibernate如何生成Sql來維護關聯的記錄!

Hibernate僅僅按照主控方對象的狀態的變化來同步更新數據庫。按照原來的映射文件,people.getAddresses().add(address),即主控方對象的狀態發生了改變,因此數據庫會跟著對象狀態的變化來同步更新數據庫;而address.setPeople(people),即被控方對象的狀態發生了改變,它是不能觸發對象和數據庫的同步更新的。

(實例1):

舉個最簡單的一對多父子關系。那麽代碼就寫成:

  1. Parent p = new Parent();
  2. Child c = new Child();
  3. c.setParent(p); //維護父子之間關系
  4. p.getChildren().add(c);
  5. session.save(p);
  6. session.flush();

映射文件配置:

  1. 父親中的關系映射
  2. {set name="children" lazy="true" inverse="true"}
  3. {key column="parent_id"/}
  4. {one-to-many class="test.Child"/}
  5. {/set}
  6. 兒子中關系映射
  7. {many-to-one name="parent" column="parent_id" not-null="true"/}

set中inverse="true",說明父子關系只在多的一端(Child)維護。所以只會發出2個insert語句。

註意:{many-to-one}總是設成“inverse=false”的,而且這個屬性在Mapping中是不存在的!

這樣運行的下來的結果就是:

  1. Hibernate: insert into parent (id) values (?)
  2. Hibernate: insert into child (parent_id, id) values (?, ?)

如果將set中的inverse設為true,那麽會發出3條sql語句,前2條是insert語句,後1條是update語句用來維護parent和child類的父子關系。

當然,假如c.setParent(p)註釋掉(破壞了父子關系),結果就變成了:

  1. Hibernate: insert into parent (id) values (?)

===================================================
(實例2):
一個Person可以參加多個Event,一個Event有多個Person參加。映射文件如下:

  1. <!-- Person.hbm.xml -->
  2. <hibernate-mapping package="events">
  3. <class name="Person" table="person">
  4. <id name="id" column="person_id">
  5. <generator class="native"/>
  6. </id>
  7. <property name="age" length="0"/>
  8. <property name="firstname"/>
  9. <property name="lastname"/>
  10. <set name="events" table="person_event">
  11. <key column="person_id"/>
  12. <many-to-many column="event_id" class="events.Event"/>
  13. </set>
  14. </class>
  15. </hibernate-mapping>
  16. <!-- Event.hbm.xml -->
  17. <hibernate-mapping>
  18. <class name="events.Event" table="events">
  19. <id name="id" column="event_id">
  20. <generator class="native"/>
  21. </id>
  22. <property name="date" column="events_date" type="timestamp"/>
  23. <property name="title" column="events_title"/>
  24. <set name="participants" table="person_event" inverse="true">
  25. <key column="event_id"/>
  26. <many-to-many column="person_id" class="events.Person"/>
  27. </set>
  28. </class>
  29. </hibernate-mapping>


inverse=true的含義: 由雙向關聯另一方維護該關聯,己方不維護該關聯(只能進行查詢操作)。在上述代碼中,由Person方維護該<many-to-many>關系,示例代碼如下(以向Person參與的Event中加入新的Event為例):

  1. Session session = HibernateUtil.getSessionFactory().getCurrentSession();
  2. session.beginTransaction();
  3. Person p = (Person) session.load(Person.class, personId);
  4. Event e = (Event) session.load(Event.class, eventId);
  5. p.getEvents().add(e);//執行該代碼時,hibernate會向中間表 person_event中插入person_id和event_id記錄,如果換成e.getParticipants().add(p)的話,該代碼將不會被執行,即hibernate不會向表person_event中插入記錄。
  6. session.getTransaction().commit();


要註意的一點:在雙向關聯的關系中,映射的column(和table)的值要一致(即要用相同的表名和列名),不然設置為inverse="true"的這方將失去這個雙向關系,而變成了一個單向關聯。

二、Inverse和Cascade的比較

Inverse:負責控制關系,默認為false,也就是關系的兩端都能控制,但這樣會造成一些問題,更新的時候會因為兩端都控制關系,於是重復更新。一般來說有一端要設為true。

Cascade:負責控制關聯對象的級聯操作,包括更新、刪除等,也就是說對一個對象進行更新、刪除時,其它對象也受影響,比如我刪除一個對象,那麽跟它是多對一關系的對象也全部被刪除。
舉例說明區別:刪除“一”那一端一個對象O的時候,如果“多”的那一端的Inverse設為true,則把“多”的那一端所有與O相關聯的對象外鍵清空;如果“多”的那一端的Cascade設為Delete,則把“多”的那一端所有與O相關聯的對象全部刪除。

一口一口吃掉Hibernate(八)——Hibernate中inverse的用法