2009-05-05 43 views
10

我有以下方式儲蓄雙向多對多

@Entity 
class A { 
    @ManyToMany(mappedBy="A", cascade=CascadeType.ALL) 
    private List<B> b; 
.. 
} 

@Entity 
class B { 
    @ManyToMany(cascade=CascadeType.ALL) 
    private List<A> a; 
.. 
} 

標註的兩個實體類如果我存儲類「B」的關係都存儲在數據庫中,並在課堂上「A」,吸氣的實例將返回B的正確子集。但是,如果我更改了'A'中的Bs列表,那麼這些更改不會存儲在數據庫中?

我的問題是,我該如何做到這一點,以便兩個班級的變化都可以「級聯」到另一個班級?

編輯:我試過刪除mappedBy參數和定義JoinTable(和列)的不同變體,但我一直無法找到正確的組合。

+0

哪些JPA實現您使用? – 2009-05-22 00:15:13

回答

16

最短的答案似乎是你不能,它是有道理的。在雙向多對多關聯中,一方必須是主人,並且用於持久更改底層連接表。由於JPA不會維護關聯的兩側,因此最終可能會導致內存情況,一旦存儲在數據庫中就無法重新加載。 例子:

A a1 = new A(); 
A a2 = new A(); 
B b = new B(); 
a1.getB().add(b); 
b.getA().add(a2); 

如果這種狀態能夠持續下去,你最終會在連接表如下條目:

a1_id, b_id 
a2_id, b_id 

但在加載時,會如何JPA知道你打算只讓b知道a2而不是a1?那麼a2不應該知道b?

這就是爲什麼您必須自己維護雙向關聯(並且使上述示例無法到達,即使在內存中),JPA也只會基於其一側的狀態持續存在。

0

你有沒有tryed您所指定的反向連接列添加的mappedBy參數到某個字段B類像這樣

@Entity 
class B { 
    @ManyToMany(cascade=CascadeType.ALL, mappedBy = "b") 
    private List<A> a; 
.. 
} 
+0

這不起作用,它實際上是一個非法參數化。 mappedBy參數定義了字段的所有權,因此兩個集合都不能使用該參數,因爲它們不能彼此擁有。 – 2009-05-05 12:43:30

3

@Entity 
class A { 
    @ManyToMany(mappedBy="A", cascade=CascadeType.ALL) 
    private List <B> b; 
    .. 
} 

@Entity 
class B { 
    @ManyToMany 
    @JoinTable (
     name="A_B", 
     joinColumns = {@JoinColumn(name="A_ID")}, 
     inverseJoinColumns = {@JoinColumn(name="B_ID")} 
    ) 
    private List<A> a; 
    .. 
} 

這是假設一個名爲A_B的連接表,列A_ID和B_ID。

+0

我曾試過這個解決方案,但沒有運氣:( – 2009-05-06 05:38:17

0

也許在A_M的答案中有一個小錯誤。 在我看來,這應該是:

 
    @Entity 
    class B { 
    @ManyToMany 
    @JoinTable (
     name="A_B", 
     joinColumns = {@JoinColumn(name="B_ID")}, 
     inverseJoinColumns = {@JoinColumn(name="A_ID")} 
    ) 
    private List a; 
    .. 
} 
1

由於工作的關係是雙向的,從而將應用程序更新的關係 一面,另一面也應得到更新, 並同步。在JPA中,如在Java中一般這是應用程序的 責任,或者維持 關係的對象模型。如果您的應用程序添加到 關係的一側,則它必須添加到另一側。

這可以通過在處理關係兩邊的對象模型 中添加或設置方法來解決,因此應用程序代碼 不需要擔心它。有兩種方法可以解決這個問題, 您只能將關係維護代碼添加到關係的一側 ,並且僅從一側使用設置器(例如使另一側受到保護的 ),或者將其添加到雙方並確保您避免無限循環。

來源:OneToMany#Getters_and_Setters