2010-06-15 55 views
1

我使用JPA(特別是Hibernate)映射了兩個實體。這些實體有一個一對多的關係(我已經簡化了演示):嘗試在「one」實體上設置「many」時奇怪的JPA一對多行爲

@Entity 
public class A { 

    @ManyToOne 
    public B getB() { return b; } 
} 

@Entity 
public Class B { 

    @OneToMany(mappedBy="b") 
    public Set<A> getAs() { return as; } 
} 

現在,我試圖通過使用單的制定者來創建這些實體的兩個實例之間的關係側/關係的不所有者側(即,表被引用於):

em.getTransaction().begin(); 

A a = new A(); 
B b = new B(); 
Set<A> as = new HashSet<A>(); 
as.add(a); 
b.setAs(as); 

em.persist(a); 
em.persist(b); 
em.getTransaction().commit(); 

但隨後,關係不保持到DB(對實體A創建的行不參照該爲實體B創建的行)。爲什麼這樣?我會尊重它的工作。

此外,如果我從@OneToMany註釋中刪除「mappedBy」屬性,它將工作。再次 - 爲什麼如此?以及刪除「mappedBy」屬性有什麼可能的影響?

回答

5

在雙向關聯中,JPA規範是這樣定義的,當實現只想查看關聯的當前「狀態」以確定什麼需要持久化並且每個雙向關聯具有關聯的擁有方時擁有和反面。這可以避免含糊不清(即,如果關聯的兩端不一致,該如何堅持?),併爲JPA實現者提供了優化和更簡單實現的機會。請注意,這通常不是問題,因爲雙向關聯應由您而不是由JPA正確維護。當您在應用程序中始終保持雙向關聯(更新雙方並保持一致)時,沒有任何問題。

OneToMany with mappedBy是一個反面,因此當確定衝突/事務提交時關聯的狀態時,JPA impl不會查看此邊。它只查看A.getB(),它是空的,所以JPA的關聯爲空。

OneToMany沒有mappedBy,所以這成爲擁有方,只支持自JPA 2.0以來,但我認爲Hibernate支持自年齡。這就是爲什麼你的例子工作,如果你從OneToMany中移除mappedBy。在這種情況下,OneToMany成爲擁有者的一方,因此實施「看着」這一方來決定要堅持什麼。 這並不會改變您的內存關聯仍然不完整的事實。你應該設置雙方。

更新:我不確切地知道Hibernate在從任何一方離開mappedBy時會做什麼,但我認爲這可能會導致不太理想的SQL。另請參閱:http://simoes.org/docs/hibernate-2.1/155.html,特別是關於「inverse =」false「」的部分。 「inverse」是JPA「mappedBy」的原生Hibernate術語。也就是說,Hibernate映射中的inverse =「true」與在JPA映射中使用mappedBy =「other」相同,都將此邊標記爲確定更新關聯時忽略的反面。

+0

感謝您的詳細解答。 沒有「mappedBy」,如果我改變了「many」方(A),他也堅持數據,所以我想它看起來都在(或者只是Hibernate?)。 毫無疑問,你應該管理你身邊的關係(在記憶中),但有時你只想保持「一邊」而不關心它的「許多」實體是否在內存中正確設置(引用他)。 – 2010-06-15 12:26:54