2008-09-16 47 views
20

有關我的earlier question,我想確保所有的子對象都被加載,因爲我有多個線程可能需要訪問數據(從而避免延遲加載例外)。我明白這樣做的方法是在查詢中使用「fetch」關鍵字(EJB QL)。就像這樣:休眠(JPA)如何做一個渴望的查詢,加載所有的子對象

select distinct o from Order o left join fetch o.orderLines 

假設有Order類有一組在它OrderLines的典範。

我的問題是,「不同」的關鍵字似乎是需要的,否則我似乎找回Order爲每個OrderLine。我做對了嗎?

也許更重要的是,有沒有辦法拉動所有的小孩物體,不管它有多深?我們有大約10-15個班級,對於服務器,我們將需要加載所有內容......我避免使用FetchType.EAGER,因爲這意味着它始終渴望並且特別是Web前端加載所有內容 - 但也許這是要走的路 - 是你做了什麼?我似乎記得我們之前嘗試過這樣做,然後獲得了非常慢的網頁 - 但也許這意味着我們應該使用二級緩存?

回答

14

更改註釋是一個壞主意IMO。因爲它不能在運行時更改爲懶惰。最好讓所有的東西都懶,並根據需要抓取。

我不確定我是否理解了您的問題,沒有映射。左連接獲取應該是您描述的用例所需的全部。當然,如果訂單行有一個訂單作爲其父母,那麼您將獲得每個訂單行的訂單。

8

我不知道如何使用您的EJBQL抓取關鍵字,你可能會得到它混淆與註釋...

您是否嘗試過加入FetchType屬性的關係屬性?

@OneToMany(fetch = FetchType.EAGER)?

參見:

http://java.sun.com/javaee/5/docs/api/javax/persistence/FetchType.html http://www.jroller.com/eyallupu/entry/hibernate_exception_simultaneously_fetch_multiple

+0

是的,這是正確的答案 – 2008-09-16 11:13:53

+6

這傢伙需要在運行時改變策略。 – Nullpo 2012-04-19 05:41:45

0

這將只爲多對一的關係,併爲他們的工作@ManyToOne(取= FetchType.EAGER)可能會適當。

渴望獲得多個OneToMany關係是不鼓勵和/或不工作,因爲你可以閱讀鏈接傑里米張貼。考慮一下執行這樣的提取所需的SQL語句...

0

我所做的是重構代碼以保持對象的映射到實體管理器,並且每次我需要刷新時關閉對象的舊實體管理器並打開一個新對象。我使用了上述查詢,但沒有提取,因爲這對我的需求來說太深了 - 只是做一個普通的加入拉動OrderLines - 提取使它更深入。

我只需要幾個對象,大約20個,所以我認爲擁有20個開放實體管理器的資源開銷並不是問題 - 儘管DBA可能在這種情況下有不同的視圖...

我也重新工作,以便數據庫工作在主線程和實體管理器。

克里斯

-4

如果問題僅僅是LazyInitializationException異常,您可以通過添加的OpenSessionInViewFilter避免這種情況。
這將允許在視圖中加載對象,但不會幫助解決速度問題。

 <filter> 
     <filter-name>hibernateFilter</filter-name> 
     <filter-class> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter 
     </filter-class> 
    </filter> 
    <filter-mapping> 
     <filter-name>hibernateFilter</filter-name> 
     <url-pattern>/*</url-pattern> 
    </filter-mapping> 
+0

謝謝,但這個答案涉及webapps/servlets,而不是一個獨立的應用程序,這是我正在與之合作。 – 2008-09-17 08:52:24

2

您可以使用(分離)條件查詢並設置獲取模式來做類似的事情。例如,

Session s = ((HibernateEntityManager) em).getSession().getSessionFactory().openSession(); 
DetachedCriteria dc = DetachedCriteria.forClass(MyEntity.class).add(Expression.idEq(id)); 
dc.setFetchMode("innerTable", FetchMode.JOIN); 
Criteria c = dc.getExecutableCriteria(s); 
MyEntity a = (MyEntity)c.uniqueResult(); 
3

您是否嘗試過使用結果轉換器?如果您使用的條件查詢,就可以申請結果變壓器(雖然there are some problems with pagination and result transformer):

Criteria c = ((Session)em.getDelegate()).createCriteria(Order.class); 
c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); 
c.list(); 

em.getDelegate()是一個黑客,只有當您使用休眠工作。

也許更重要的是,有沒有在所有子對象拉 辦法,沒有 無論多深?我們有大約10-15 類和我們 需要的一切加載在服務器...我是 使用FetchType.EAGER作爲 意味着它總是渴望和 特別是web前端負載 避免一切 - 但也許那就是 的路要走 - 是你在做什麼? I 似乎記得我們在 之前嘗試此操作,然後變得非常緩慢的網頁 - 但也許這意味着我們應該使用二級緩存?

如果您還有興趣,我回復了一個類似的問題,在這個線程how to serialize hibernate collections

基本上你使用了一個叫做dozer的工具,它將bean映射到另一個bean上,通過這樣做,你可以觸發你所有的惰性負載。正如你可以想象的,如果所有的集合都被熱切地提取出來,這會更好。