簡體   English   中英

Hibernate(JPA)如何做一個急切的查詢,加載所有子對象

[英]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”關鍵字,否則我似乎會收到每個OrderLineOrder 我做對了嗎?

也許更重要的是,有沒有辦法拉入所有兒童物品,無論多深? 我們有大約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.

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