2009-10-07 49 views
11

我在我的數據模型中有兩個名爲User和UserProfile的實體。這是他們如何映射。從用戶實體關於JPA級聯的問題

代碼:從用戶配置實體

@OneToOne(cascade=CascadeType.ALL) 
@PrimaryKeyJoinColumn 
public UserProfile getUserProfile(){ 
    return this.userProfile; 
} 

public void setUserProfile(UserProfile userProfile){ 
    this.userProfile=userProfile; 
} 

代碼:

@OneToOne(mappedBy="userProfile",cascade=CascadeType.ALL) 
public User getUser(){ 
    return this.user; 
} 

public void setUser(User user){ 
    this.user=user; 
} 

正如你看到的,我有一個在用戶配置用戶屬性的cascadetype.all。但是當我嘗試刪除UserProfile實體時,相應的User實體仍然保留。 (當我嘗試刪除用戶實體,相應的用戶配置實體被刪除。)

這裏是我的問題: -

  • 做級聯只能容納當我擁有的關係,實體指定它們?
+2

你自己的證據會表明答案是「是」 – skaffman 2009-10-07 22:38:47

+0

@skaffman .....所以,這是所有者和ownedBy概念背後的唯一原因嗎?或者還有其他嗎?謝謝。 – soontobeared 2009-10-07 23:02:23

回答

3

至於說

當我嘗試刪除用戶配置實體,相應的用戶實體仍然停留

也許當你嘗試刪除一個用戶配置你從一開始的完整性約束違規數據庫 - 你在MySQL中使用MyISAM引擎嗎?

但是,你並沒有提到它。也許你的UserProfile實體沒有對用戶實體的引用。

如JPA說明書所述

remove操作被級聯到由X引用的實體,如果從X到這些其他實體的關係與所述級聯= REMOVE或級聯註釋= ALL註釋元素值

喜歡的東西

UserProfile up = entityManager.find(UserProfile.class, id); 

entityManager.close(); 

// Notice User is null outside a persistence context 
// So user will be not removed from the database because UserProfile does not have a reference to it 
up.setUser(null); 

entityManager.getTransaction().begin(); 

entityManager.remove(up); 

entityManager.getTransaction().commit(); 

或者你有像

entityManager.getTransaction().begin(); 

UserProfile up = entityManager.find(UserProfile.class, id); 

// throws UPDATE USER_PROFILE SET USER_ID = NULL 
up.setUser(null); 

// up.getUser() is null 
// So user is not removed 
entityManager.remove(up); 

entityManager.getTransaction().commit(); 

針對ChhsPly的評論:

在Java持久性與Hibernate的書,您會看到以下

級聯屬性是有方向性的:它適用於只有一個下場協會

我認爲這將是更好,因爲

它適用於足協的只有一端每個操作

所以,你可以在同一把cascade屬性在兩側時間,即使是雙向關係。所以ChssPly是對的。

mappdeBy屬性建立雙向關係。 mappedBy屬性將Address實體指定爲關係的反面。這意味着客戶實體是這種關係的主體。

ChssPly是正確的,他說:的mappedBy無關與級聯

+0

這是不正確的。首先,'mappedBy'與級聯無關 - 它用來表示雙向關係的非所有者一方。其次,「級聯」屬性是**屬性**(如「不是關聯」),因此它本身不是單向的或雙向的。它可以應用於單向或雙向關聯(包括雙方同時)。某些級聯**類型**在非所有者協會方面可能沒有意義。 – ChssPly76 2009-10-08 02:19:43

+0

謝謝你,ChssPly。由於我是非英語母語的人,因此在編寫答案時我有一些限制。添加到原來的答案。 – 2009-10-08 05:02:16

+0

@Arthur - 感謝您的編輯(upvoting);我的意思並不是要苛刻或挑剔 - 只是想澄清一些觀點。英語不是我的第一語言:-) – ChssPly76 2009-10-08 06:20:11

1

這是正確的,當你有一個雙向關係的所有者決定了級聯規則,因爲它是「老闆」。 「擁有」的實體基本上遵從命令,它不能下達命令 - 可以這麼說。

15

你的問題本身是錯誤的,這是所有混淆源於的地方。 Arthur的回答做得很好,但從評論中可以清楚地看出混亂仍然存在,所以讓我在這裏嘗試一下。

做級聯持有,只有當我指定 他們擁有的 關係的實體?

「級聯」是您在關係的一個(或雙向)情況下指定的屬性。它決定了什麼動作上執行結束將傳播到其他結束。在JPA中定義的動作有many different types,在Hibernate擴展中定義了even more。這種區別很重要 - 您應該只討論特定的傳播的行爲,而不是一般的「級聯」。

PERSIST,MERGE,REFRESH正常傳播(從最後宣佈到另一個)。

然而,REMOVE是棘手的,因爲它可能意味着兩個不同的東西。如果你有一個B之間的關係和你想刪除一個,你可以刪除在另一端,也可以刪除該協會但留下完好。 Hibernate在兩者之間做了明確的區分 - 您可以分別聲明REMOVE(DELETE)和DELETE_ORPHAN級聯類型; JPA規範沒有。請注意,DELETE_ORPHAN不支持單值關係(OneToOne/ManyToOne)。因此,REMOVE的傳播(單獨或當它是ALL的一部分時)取決於關係是否具有明確的所有者(單向始終如此;如果使用mappedBy進行映射則雙向執行並且如果它是映射通過連接表),在這種情況下,它從所有者傳播到擁有者或沒有所有者,在這種情況下,它向任一方向傳播,但沒有語義,除非它被明確指定。後者的典型例子是雙向的多對多。

+0

嗨Chss,我已經嘗試在這裏,工作正常 - OneToOne和ManyToMany。雖然我使用Hibernate,但我認爲它在JPA中的工作方式相同,因爲hibernate是JPA的超集。我認爲最好能否儘快顯示代碼,試圖刪除UserProfile及其引用的User實體。可能是應用程序拋出了約束違規,並且未刪除引用的用戶實體。假設它發生了什麼,也很難。問候, – 2009-10-09 00:25:33

+0

...沒有。 Hibernate是JPA的實現,這與「超集」無關 - 甚至沒有任何意義 – specializt 2013-07-03 10:11:05

+1

如果您更新答案以反映當前JPA 2的孤兒行爲,那將會很不錯。 – 2013-07-10 16:38:14

0

使用JPA 2.x中,如果你想級聯拆後使用orphanRemoval屬性:

@OneToMany(orphanRemoval=true)

檢查文檔here獲取更多信息。