20

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

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

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

我的问题是似乎需要“distinct”关键字,否则我似乎会得到一个Orderfor each OrderLine。我在做正确的事吗?

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

4

7 回答 7

15

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

如果没有映射,我不确定我是否理解您的问题。对于您描述的用例,左连接提取应该是您所需要的。当然,如果 orderline 有一个订单作为其父级,您将获得每个 orderline 的订单。

于 2008-09-16T11:50:07.303 回答
8

我不确定在您的 EJBQL 中使用 fetch 关键字,您可能会将它与注释混淆......

您是否尝试将 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

于 2008-09-16T10:53:51.197 回答
3

您是否尝试过使用结果转换器?如果您使用 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 前端加载所有内容 - 但也许这就是要走的路- 那是你做的吗?我似乎记得我们之前尝试过这个然后得到非常慢的网页 - 但这也许意味着我们应该使用二级缓存?

如果您仍然感兴趣,我在这个线程如何序列化休眠集合中回答了一个类似的问题。

Basically you use a utility called dozer that maps beans onto another beans, and by doing this you trigger all your lazy loads. As you can imagine, this works better if all collections are eagerly fetched.

于 2008-10-22T22:34:23.907 回答
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();
于 2008-09-16T18:28:08.360 回答
0

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

不鼓励急切地获取多个 OneToMany 关系和/或不起作用,正如您可以在 Jeremy 发布的链接中看到的那样。想想执行这样的提取所需的 SQL 语句......

于 2008-09-16T11:18:03.667 回答
0

我所做的是重构代码以将对象映射到实体管理器,并且每次我需要刷新时,关闭对象的旧实体管理器并打开一个新的。我使用了没有获取的上述查询,因为这对我的需要来说太深了——只是在 OrderLines 中做一个简单的连接——获取使它变得更深。

只有少数几个对象需要这个,大约 20 个,所以我认为拥有 20 个开放实体管理器的资源开销不是问题——尽管当它上线时 DBA 可能会有不同的看法......

我还重新设计了一些东西,以便数据库工作在主线程上并具有实体管理器。

克里斯

于 2008-09-16T14:58:00.020 回答
-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>
于 2008-09-16T16:34:22.300 回答