2012-11-07 40 views
1

在保持單向@ManyToMany關係方面存在問題。我將EclipseLink 2.3與Spring數據和MySQL一起使用。JPA:堅持重複使用的收集項目@ManyToMany

實體僞代碼:

@Entity 
public class Subscriber { 
@Id @GeneratedValue(strategy = GenerationType.AUTO) 
private Long id; 

@ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST}) 
private List<SubscribersList> subscribersLists; 

//...shortened... 
} 

@Entity 
public class SubscribersList { 
@Id @GeneratedValue(strategy = GenerationType.AUTO) 
private Long id; 
private String title; 

//...shortened... 
} 

未來在一些服務創建新的列表和兩個用戶...

list = new SubscribersList("DEFAULT"); 
s1 = new Subscriber(); 
s1.getSubscribersList().add(list); //empty list is created in the constructor 
repository.save(s1); //works ok 
s2 = new Subscriber(); 
s2.getSubscribersList().add(list); 
repository.save(s2); //fails with Duplicate entry '2' for key 'PRIMARY' 

保存第一用戶後,列表將成爲管理的實體,但儘管這樣的保存第二個用戶JPA試圖再次創建列表:

Call: INSERT INTO SUBSCRIBERSLIST (ID, DESCRIPTION, TITLE) VALUES (?, ?, ?) 
bind => [2, null, DEFAULT] 

Interesti恩我的內存測試hsqldb的作品。顯然我錯過了一些東西,但不能發現問題...

回答

0

save()是做什麼的?

這個問題很可能是你的對象被分解了,所以從來沒有分配它們的ID,所以沒有任何關聯它們的託管對象。

您需要堅持而不是合併它們(並確保您使用未分離的託管對象)。或者返回id,或者在保存後執行查找,以確保您使用的是有效的對象。

+0

'save()'將persist()和merge()與內部邏輯合併,決定使用哪一個。我對代碼做了輕微的修改:從'@ ManyToMany'中刪除了'CascadeType.PERSIST',因此需要先保存子列表列表,然後將持久訂閱者列表設置爲新創建的訂閱者,然後將訂閱者持久化。 – marek

+0

所以在我身邊可能存在一些JPA如何工作的誤解......我想,當我創建新的對象被持久化,並將對象圖放在一些已經持久化的實體(在我的情況下是subscribersList)時,JPA足夠聰明來管理它... – marek

+0

你不能破壞你的持久性單元中的對象。任何託管對象或新持久對象都應只引用其他託管對象。 Merge()會爲你解決問題,但會返回被管理的分離對象的副本。 – James