Hibernate(JPA)如何做一个急切的查询,加载所有子对象

时间:2008-09-16 10:21:48

标签: java hibernate jpa ejbql

关于我的earlier question,我想确保加载所有子对象,因为我有一个可能需要访问数据的多个线程(从而避免延迟加载异常)。我知道这样做的方法是在查询中使用“fetch”关键字(EJB QL)。像这样:

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

假设一个Order类的模型中有一组OrderLines

我的问题是,似乎需要“distinct”关键字,否则我似乎会为每个Order取回OrderLine。我做对了吗?

也许更重要的是,有没有办法拉入所有儿童物品,无论多深?我们有大约10-15个类,对于服务器,我们将需要加载所有内容...我避免使用FetchType.EAGER,因为这意味着它总是渴望,特别是Web前端加载所有内容 - 但也许这就是方式去 - 你做的是什么?我似乎记得我们之前尝试过这个,然后得到非常慢的网页 - 但也许这意味着我们应该使用二级缓存?

7 个答案:

答案 0 :(得分:14)

改变注释是一个坏主意IMO。因为它无法在运行时更改为惰性。最好让一切都变得懒惰,并根据需要进行获取。

如果没有映射,我不确定我是否理解你的问题。左连接提取应该是您描述的用例所需的全部内容。当然,如果订单行以订单作为其订单,您将获得每个订单行的订单。

答案 1 :(得分:8)

我不确定在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

答案 2 :(得分:3)

您是否尝试使用结果转换器?如果使用Criteria查询,则可以应用结果转换器(尽管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   意味着它总是渴望和进入   特别是网络前端加载   一切 - 但也许就是这样   要走的路 - 你做的是什么?一世   似乎记得我们以前尝试过这个   然后得到非常慢的网页    - 但也许这意味着我们应该使用二级缓存?

如果您仍然感兴趣,我在此主题how to serialize hibernate collections中回答了类似的问题。

基本上,您使用名为dozer的实用程序将bean映射到另一个bean,并通过这样做触发所有延迟加载。如你所能想象的那样,如果所有的集合都被热切地提取,这种方法会更好。

答案 3 :(得分: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();

答案 4 :(得分:0)

这只适用于ManyToOne关系,对于他们来说@ManyToOne(fetch = FetchType.EAGER)可能是合适的。

劝阻不止一个OneToMany关系,并且/或者不能正常工作,因为您可以阅读Jeremy发布的链接。只要想想进行这样一次获取所需的SQL语句......

答案 5 :(得分:0)

我所做的是重构代码以保持对象映射到实体管理器,每次我需要刷新时,关闭对象的旧实体管理器并打开一个新对象。我在没有 fetch 的情况下使用了上述查询,因为这对我的需求来说太深了 - 只需在OrderLines中进行普通连接 - fetch 使其更深入。

我只需要几个对象,大约20个,所以我认为拥有20个开放实体管理器的资源开销不是问题 - 尽管DBA在生效时可能有不同的视图... < / p>

我还重做了一些事情,以便db工作在主线程上并具有实体管理器。

克里斯

答案 6 :(得分:-4)

如果问题只是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>
相关问题