[英]Hibernate (JPA) how to do an eager query, loading all child objects
關於我之前的問題 ,我想確保加載所有子對象,因為我有一個可能需要訪問數據的多個線程(從而避免延遲加載異常)。 我知道這樣做的方法是在查詢中使用“fetch”關鍵字(EJB QL)。 像這樣:
select distinct o from Order o left join fetch o.orderLines
假設一個具有Order
類的模型,其中包含一組OrderLines
。
我的問題是似乎需要“distinct”關鍵字,否則我似乎會收到每個OrderLine
的Order
。 我做對了嗎?
也許更重要的是,有沒有辦法拉入所有兒童物品,無論多深? 我們有大約10-15個類,對於服務器,我們將需要所有加載...我避免使用FetchType.EAGER
因為這意味着它總是渴望,特別是Web前端加載一切 - 但也許這是要走的路 - 你做的是什么? 我似乎記得我們之前嘗試過這個,然后得到非常慢的網頁 - 但也許這意味着我們應該使用二級緩存?
更改注釋是IMO的一個壞主意。 因為它無法在運行時更改為惰性。 最好讓一切都變得懶惰,並根據需要進行獲取。
沒有映射,我不確定我理解你的問題。 左連接提取應該是您描述的用例所需的全部內容。 如果訂單行有一個訂單作為其父訂單,您當然會收到每個訂單行的訂單。
我不確定在EJBQL中使用fetch關鍵字,可能會讓它與注釋混淆...
您是否嘗試將FetchType屬性添加到關系屬性中?
@OneToMany(取= 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
你嘗試過使用結果變壓器了嗎? 如果使用Criteria查詢,則可以應用結果轉換器(盡管分頁和結果轉換器存在一些問題 ):
Criteria c = ((Session)em.getDelegate()).createCriteria(Order.class);
c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
c.list();
em.getDelegate()
是一個只在你使用hibernate時才有效的hack。
也許更重要的是,有沒有辦法拉入所有兒童物品,無論多深? 我們有大約10-15個類,對於服務器,我們將需要所有加載...我避免使用FetchType.EAGER,因為這意味着它總是渴望,特別是Web前端加載一切 - 但也許這是要走的路 - 你做的是什么? 我似乎記得我們之前嘗試過這個,然后得到非常慢的網頁 - 但也許這意味着我們應該使用二級緩存?
如果您仍然感興趣,我在這個帖子中回答了一個類似的問題, 如何序列化hibernate集合 。
基本上,您使用一個名為dozer的實用程序將bean映射到另一個bean,並通過這樣做觸發所有延遲加載。 可以想象,如果所有集合都被熱切地提取,這樣會更好。
您可以使用(分離的)條件查詢執行類似的操作,並設置獲取模式。 例如,
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();
這只適用於ManyToOne關系,對於他們來說@ManyToOne(fetch = FetchType.EAGER)可能是合適的。
急切地獲取一個以上的OneToMany關系是不鼓勵和/或不起作用,因為你可以閱讀Jeremy發布的鏈接。 只要想想進行這樣一次獲取所需的SQL語句......
我所做的是重構代碼以保持對象映射到實體管理器,每次我需要刷新時,關閉對象的舊實體管理器並打開一個新對象。 我使用了上面的查詢而沒有獲取,因為這對我的需求來說太深了 - 只需要在OrderLines中進行普通連接 - 獲取使得它更深入。
我需要的對象只有幾個,大約20個,所以我認為擁有20個開放實體管理器的資源開銷不是問題 - 盡管DBA在生效時可能有不同的視圖......
我還重新處理了一些事情,以便db工作在主線程上並具有實體管理器。
克里斯
如果問題只是LazyInitializationExceptions,則可以通過添加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>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.