簡體   English   中英

JPA /休眠父母/子女關系

[英]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;

    /* ..... */

}

我希望能夠執行以下操作:

  1. 檢索包含所有子項列表(列表)的父實體,但是,在列出父項(獲取列表)時,它當然應該從結果中省略子項,因此設置FetchType.LAZY。

  2. 檢索將包含父實體實例的子實體。

使用上面的代碼(或類似代碼)會導致兩個異常:

  1. 檢索父對象:在對象圖中檢測到一個循環。 這將導致無限深的XML ...

  2. 檢索子級: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船

  • 父母-1:n->孩子
  • 孩子-n:1->父母

兩者都是獨立的,但存儲在同一“數據庫”列中。

我想這不是您想要的,我想您想要一個雙向關系 該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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM