Java Hibernate (JPA) 如何进行急切查询,加载所有子对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/70992/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 07:56:51  来源:igfitidea点击:

Hibernate (JPA) how to do an eager query, loading all child objects

javahibernatejpaejbql

提问by Chris Kimpton

Relating to my earlier question, I want to ensure all the child objects are loaded as I have a multiple threads that may need to access the data (and thus avoid lazy loading exceptions). I understand the way to do this is to use the "fetch" keyword in the query (EJB QL). Like this:

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

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

Assuming a model with an Orderclass which has a set of OrderLinesin it.

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

My question is that the "distinct" keyword seems to be needed as otherwise I seem to get back an Orderfor each OrderLine. Am I doing the right thing?

我的问题是似乎需要“distinct”关键字,否则我似乎会Order为每个OrderLine. 我在做正确的事吗?

Perhaps more importantly, is there a way to pull in all child objects, no matter how deep? We have around 10-15 classes and for the server we will need everything loaded... I was avoiding using FetchType.EAGERas that meant its always eager and in particular the web front end loads everything - but perhaps that is the way to go - is that what you do? I seem to remember us trying this before and then getting really slow webpages - but perhaps that means we should be using a second-level cache?

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

采纳答案by James Law

Changing the annotation is a bad idea IMO. As it can't be changed to lazy at runtime. Better to make everything lazy, and fetch as needed.

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

I'm not sure I understand your problem without mappings. Left join fetch should be all you need for the use case you describe. Of course you'll get back an order for every orderline if orderline has an order as its parent.

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

回答by Jeremy

I'm not sure about using the fetch keyword in your EJBQL, you might be getting it confused with the annotation...

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

Have you tried adding the FetchType property to your relationship attribute?

您是否尝试将 FetchType 属性添加到您的关系属性中?

@OneToMany(fetch=FetchType.EAGER)?

@OneToMany(fetch=FetchType.EAGER)?

See:

看:

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

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

回答by jrudolph

That would only work for ManyToOne relations and for them @ManyToOne(fetch=FetchType.EAGER) would probably appropriate.

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

Fetching more than one OneToMany relation eagerly is discouraged and/or does not work as you can read in the link Jeremy posted. Just think about the SQL statement that would be needed to do such a fetch...

正如您可以在 Jeremy 发布的链接中阅读的那样,不鼓励和/或不鼓励获取多个 OneToMany 关系。想想执行这种获取所需的 SQL 语句......

回答by Chris Kimpton

What I have done is to refactor the code to keep a map of objects to entity managers and each time I need to refresh, close the old entitymanager for the object and open a new one. I used the above query without the fetchas that is going too deep for my needs - just doing a plain join pulls in the OrderLines - the fetchmakes it go even deeper.

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

There are only a few objects that I need this for, around 20, so I think the resource overhead in having 20 open entitymanagers is not an issue - although the DBAs may have a different view when this goes live...

我只需要几个对象,大约 20 个,所以我认为拥有 20 个打开的实体管理器的资源开销不是问题 - 尽管 DBA 可能有不同的看法。

I also re-worked things so that the db work is on the main thread and has the entity manager.

我还重新工作,以便数据库工作在主线程上并具有实体管理器。

Chris

克里斯

回答by ncgz

If the problem is just LazyInitializationExceptions, you can avoid that by adding an OpenSessionInViewFilter.
This will allow the objects to be loaded in the view, but will not help with the speed issue.

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

回答by Mike Desjardins

You might be able to do something like that using a (detached) criteria query, and setting the fetch mode. E.g.,

您可以使用(分离的)条件查询并设置提取模式来执行类似的操作。例如,

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();

回答by Miguel Ping

Have you tried using a result transformer? If you use Criteria queries, you can apply a result transformer (although there are some problems with pagination and result transformer):

您是否尝试过使用结果转换器?如果使用 Criteria 查询,则可以应用结果转换器(尽管分页和结果转换器存在一些问题):

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

the em.getDelegate()is a hack that only works if you are using hibernate.

em.getDelegate()是一个只有在您使用休眠时才有效的黑客。

Perhaps more importantly, is there a way to pull in all child objects, no matter how deep? We have around 10-15 classes and for the server we will need everything loaded... I was avoiding using FetchType.EAGER as that meant its always eager and in particular the web front end loads everything - but perhaps that is the way to go - is that what you do? I seem to remember us trying this before and then getting really slow webpages - but perhaps that means we should be using a second-level cache?

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

If you are still interested, I responded a similar question in this thread how to serialize hibernate collections.

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

Basically you use a utility called dozerthat 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.

基本上,您使用名为dozer的实用程序将 bean 映射到另一个 bean,通过这样做,您会触发所有延迟加载。可以想象,如果所有集合都被急切地获取,这会更好。