cascade 的意義


在Java程式中,物件與物件之間會透過某些關係互相參考,如果有一個物件已經是持久化物件,被它參考的物件直覺上也應該要持久化,以維持物件之間關聯的 完整性,這是藉由可達性完成持久化(Persistence by reachability)的基本概念。

如果將物件之間的關聯想像為一個樹狀圖,從某一個持久化物件為樹根出發,父節點若是持久化物件,則被父節點參考到的子節點應自動持久化,而另一方面,如果 有一子節點沒辦法藉由任何的父節點來參考至它,則它沒有被持久化的需求,它應從資料庫中加以刪除。

完整的掃描物件圖中的所有物件是否該持久化,牽涉到記憶體與資料庫中所有相關表格的掃描,在效能上無法接受這樣的概念,所以Hibernate並沒有完全 實現以上的概念,它讓使用者自行決定自動持久化的方式,當物件之間被指定關聯(例如多對一、一對多等),您可以決定被持久化 物件關聯的暫存對象是否進行自動持久化與如何自動持久化。

在Hibernate中是以映射文件中標籤上的cascade屬性來設定,預設上是none,以 多對一 中的範例來說,如果不設定cascade為true,則您必須分別對User實例與Room實例進行儲存:
Room room1 = new Room();
room1.setAddress("NTU-M8-419");
Room room2 = new Room();
room2.setAddress("NTU-G3-302");
       
User user1 = new User();
user1.setName("bush");
user1.setRoom(room1);
       
User user2 = new User();
user2.setName("caterpillar");
user2.setRoom(room1);
       
User user3 = new User();
user3.setName("momor");
user3.setRoom(room2);

Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();

// 儲存Room實例
session.save(room1);
session.save(room2);        
// 儲存User實例
session.save(user1); 
session.save(user2);
session.save(user3);
       
tx.commit();
session.close();

cascade屬性需要設置多個值時,可以使用逗號區隔,例如:
        <many-to-one name="room"
                     column="room_id"
                     class="onlyfun.caterpillar.Room"
                     cascade="save-update, pesist, merge"
                     outer-join="true"/>

使用cascade自動持久化時,會先檢查被關聯物件的id屬性,未被持久化的物件是否儲存是藉由id屬性的unsaved-value決定,預設是 null,也就是沒有參考至任何值時儲存物件,如果您使用int、long這樣的原生型態(Primitive type)時,由於資料成員的初始會被設定為0,所以您必須自行指定預設值,例如(如果id的資料型態是long的話):
....
        <id name="id" column="id" unsaved-value="0">
            <generator class="native"/>
        </id>
....