2013-01-07 29 views
4

在說明「在查詢中指定提取類型」的行之前,請先閱讀。那不是我所追求的。在休眠模式下在運行時急切加載整個對象圖

我正在尋找一種方法來加載一個完整的對象圖(對象+它的所有孩子以及他們所有的孩子等等)。我想不是想枚舉所有要加載的屬性。我直到運行時才知道它們。

N + 1查詢不是問題。但在這個神奇的操作結束時,我不希望我的圖中留下一個代理或懶惰的集合。

應該可以編寫一些代碼,以反射方式並遞歸地查看所有屬性。但收藏品使這個尷尬和複雜。

有些人推薦這種東西的推土機,但這似乎有點過分,所以我想把它作爲最後的手段。

回答

0

一個簡單的解決方案是爲所有集合(1:N和N:M)和關聯(1:1)指定lazy="false"

對於每筆交易,將會將整個圖加載到內存中。所以爲了正常工作,最多隻能有一次交易,否則會嚴重影響業績。

雖然這會做你想做的事,但成本可能太高。請注意,您可以使用「獲取配置文件」在運行時選擇不同的策略,但Hibernate在請求對象時始終會提供一份副本以供您使用,因此每次都必須複製圖表。

對我來說,這聽起來像Hibernate只是任務的錯誤工具。使用Hibernate映射實體很方便,但是以Hibernate爲代價泄漏到模型和業務代碼中。如果Hibernate強加的約束條件不適合您的賬單,那麼您應該查看別處。

也許你可以用Record類型而不是完全充實的Java bean。如果是這樣,那麼你可以看看jOOQframeworks that implement the "active record" pattern

如果您需要bean並且不受限於某種類型的數據庫,請嘗試使用OO數據庫,如db4o

最後,爲什麼要使用SQL呢?如果你總是需要整個對象圖,爲什麼不簡單地將它序列化到一個文件並在啓動時加載它?或使用memory-resident database

+0

這不是一個選項。這棵樹很複雜,只有一個我想解決整個事情的例子。 Hibernate適合99%的賬單,但有一些邊緣情況需要加載和緩存複雜圖形的分離副本。如果沒有其他人對此感到困擾,那麼當我完成後,我只需要去反射路線並在這裏發佈代碼。 – Nim

+0

您可以嘗試從Hibernate中提取運行時配置,因爲該配置已包含獲取所有引用所需的全部信息。當我用Hibernate 3.5試過這個時,我很快遇到了私人類/領域,這太難了,但也許API爲4.x打開。 –

+0

@Nim:你能找到問題的解決方案嗎?我也面臨這個問題。 –

0

我曾經需要類似的東西,我不得不使用反射來解決它。在我的情況下,我使用hql來檢索記錄。另外,這是我爲加載記錄定義爲延遲加載而創建的一種方法,因此您可能需要修改第一個方法以便不查找FetchType.LAZY屬性,並始終無論如何都可以獲取它。

我建立的方法之一將「準備」懶取。基本上有兩種方法:在@ManyToOne上使用hql上的「left join fetch」,在@OneToMany和@ManyToMany上使用hibernate.initialize()。

所以,這第一個方法返回一個字符串,其中包含hql所需的「left john fetch」es,並且還構建了一個nToMany字段的列表,該字段必須在執行查詢後由Hibernate.initialize()調用。

private String buildLazyFetch(Class<? extends GenericEntity> entityClass, List<String> nToManyFields) { 
    String lazyFetches = new String(); 
    lazyFetches += " fetch all properties "; 
    // iterate through all fields looking for lazy loaded relationships 
    for (Field f : entityClass.getDeclaredFields()) { 
     ManyToOne manyToOne = f.getAnnotation(ManyToOne.class); 
     if (manyToOne != null) { 
      if (manyToOne.fetch().equals(FetchType.LAZY)) { 
       lazyFetches += " left join fetch t." + f.getName() + " "; 
      } 
     } 
     OneToMany oneToMany = f.getAnnotation(OneToMany.class); 
     if (oneToMany != null) { 
      if (oneToMany.fetch().equals(FetchType.LAZY)) { 
       nToManyFields.add(f.getName()); 
      } 
     } 
     ManyToMany manyToMany = f.getAnnotation(ManyToMany.class); 
     if (manyToMany != null) { 
      if (manyToMany.fetch().equals(FetchType.LAZY)) { 
       nToManyFields.add(f.getName()); 
      } 
     } 
    } 
    return lazyFetches; 
} 

並執行HQL後,致電:

private void lazyFetchNToMany (List<String> nToManyFields, GenericEntity entity) { 
    for (String field : nToManyFields) { 
     try { 
      Hibernate.initialize(BeanUtils.getProperty(entity, field)); 
     } catch (HibernateException e) { 
      e.printStackTrace(); 
     } catch (IllegalAccessException e) { 
      e.printStackTrace(); 
     } catch (InvocationTargetException e) { 
      e.printStackTrace(); 
     } catch (NoSuchMethodException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

我明白這不是正是你所期待的,但它可能會幫助你的情況下,你沒有找到你想要的解決方案