[英]JPA/Hibernate Parent/Child relationship
我對JPA / Hibernate(一般來說是Java)比較陌生,所以我的問題如下(請注意,我進行了廣泛搜索,沒有找到答案):
我有兩個實體:
父母與子女(命名已更改)。
父級包含子級列表,並且子級指代父級。
例如
@Entity
public class Parent {
@Id
@Basic
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "PARENT_ID", insertable = false, updatable = false)
private int id;
/* ..... */
@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
@JoinColumn(name = "PARENT_ID", referencedColumnName = "PARENT_ID", nullable = true)
private Set<child> children;
/* ..... */
}
@Entity
public class Child {
@Id
@Basic
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "CHILD_ID", insertable = false, updatable = false)
private int id;
/* ..... */
@ManyToOne(cascade = { CascadeType.REFRESH }, fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "PARENT_ID", referencedColumnName = "PARENT_ID")
private Parent parent;
/* ..... */
}
我希望能夠執行以下操作:
檢索包含所有子項列表(列表)的父實體,但是,在列出父項(獲取列表)時,它當然應該從結果中省略子項,因此設置FetchType.LAZY。
檢索將包含父實體實例的子實體。
使用上面的代碼(或類似代碼)會導致兩個異常:
檢索父對象:在對象圖中檢測到一個循環。 這將導致無限深的XML ...
檢索子級:org.hibernate.LazyInitializationException:無法延遲初始化角色集合:xxxxxxxxxxx,沒有會話或會話被關閉
檢索父實體時,我使用一個命名查詢(即專門調用它)@NamedQuery(name =“ Parent.findByParentId”,查詢=“從父AS選擇p從AS左聯接獲取p.children,其中p.id =: ID”)
獲取父級(即服務層)的代碼:
public Parent findByParentId(int parentId) {
Query query = em.createNamedQuery("Parent.findByParentId");
query.setParameter("id", parentId);
return (Parent) query.getSingleResult();
}
盡管將Parent實體上的List屬性設置為Lazy(在檢索Child實體時),為什么會出現LazyInitializationException事件?
例外1.您的XML序列化在JPA / Hibernate中沒有任何內容,您將能夠成功地序列化雙向設置。 如果自動序列化失敗,請以某種方式預處理您要序列化的對象,以便在事務之外刪除子級到父級之間的鏈接(假設您的容器中有自動合並)。
例外2。您應該閱讀事務。 簡而言之,有規則規定何時可以遍歷需要與數據庫交互的對象,而不能完成。 從邏輯上講,這種分歧必須存在。 如果您希望懶惰的關系在事務會話之外表現為“正常”(讀取:已獲取),則可以通過遍歷或訪問該關系以解決該關系的方式來簡單地“預取”該關系。 例如,在集合或列表上調用.size或遍歷成員,即可執行此操作。
我有同樣的問題。 實際上,我有一個單向關系(例如:部門有很多員工)。 因此,員工將在Department上具有外鍵。 生成后,Hibernate與ManyToOne和OneToMany建立雙向關系。 因此,檢查您與單向或雙向天氣的關系。 在第一種情況下,您需要刪除映射oneToMany(來自部門)
希望對您有所幫助。
添加
您的映射有點奇怪。 您的映射描述的是兩種不同的單向Reelation船 :
兩者都是獨立的,但存儲在同一“數據庫”列中。
我想這不是您想要的,我想您想要一個雙向關系 。 該easyest辦法是改變家長的孩子集映射,使用mappedBy
代替@JoinColumn
:
@Entity
public class Parent {
...
/* fetch = FetchType.LAZY is default in one:many */
@OneToMany(cascade = { CascadeType.ALL }, mappedBy="parent")
private Set<child> children;
...
}
從您在我的舊答案的注釋中描述的內容來看,這應該可以解決問題。 因為如果現在通過naviagate Parant-> Child-> Parent,兩個父級將是相同的,並且持久性提供程序也知道這一點。
請注意,現在這種關系僅在子方面保持。
舊
當您收到LazyInitializationException
,問題是未加載的實體不再連接到EntityManager。 在大多數情況下,問題在於在加載實體之前關閉了事務。
您可以先做一些事情:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.