I’m facing a problem, I have a query in JPA. as I have some collections I need to use left join fetch or inner join fetch
My problem is in using the setFirstResult and setMaxResult in order to bring back a precise number of result. every time i see the whole result is bring back AND only AFTER the maxResult is used.
Is there any way to make the maxResult before ?
Thanks a lot !
here it is more information :
my problem is when i use that :
startIndex = 0;
maxResults = 10;
query.setFirstResult(startIndex);
query.setMaxResults(maxResults);
I see this message in my log :
7 juin 2011 09:52:37 org.hibernate.hql.ast.QueryTranslatorImpl list
ATTENTION: firstResult/maxResults specified with collection fetch;
applying in memory!
I see the 200 result coming back (in log) and after in the HashSet i have finally the 10 result i ask.
its seems in memory is bring back the 200 result and after the maxResults is applied in memory.
I’m searching if there is any way to be able to fetch and limit the number of result.
I used a workaround, I make a first query to ask the id of my order , without any fetch, used the maxResult.
everything work perfectly it’s used the limit instruction.
After I use my “big” query with the fetch and limit the result inside the list of id bring back in the first one.
here it is my full query without my workaround (notice that there is no limit generated as talk by @Bozho ):
select o from Order o
left join fetch o.notes note
left join fetch o.orderedBy orderedBy
left join fetch orderedBy.address addressOrdered
left join fetch orderedBy.language orderedByLg
left join fetch orderedByLg.translations orderedByLgTtrad
left join fetch o.deliveredTo deliveredTo
left join fetch deliveredTo.address addressDelivered
left join fetch deliveredTo.language deliveredToLg
left join fetch deliveredToLg.translations
left join fetch o.finalReceiptPlace finalReceiptPlace
left join fetch finalReceiptPlace.address addressFinalReceiptPlace
left join fetch finalReceiptPlace.language finalReceiptPlaceLg
left join fetch finalReceiptPlaceLg.translations
inner join fetch o.deliveryRoute delivery
left join fetch delivery.translations
inner join fetch o.type orderType
left join fetch orderType.translations
inner join fetch o.currency currency
left join fetch currency.translations
left join fetch o.attachments
left join fetch note.origin orig
left join fetch orig.translations
left join fetch o.supplier sup
left join fetch sup.department dep
left join fetch o.stateDetail stateD
inner join fetch stateD.state stat
where 1=1 and o.entryDate >= :startDat
To understand why Hibernate does this, you need to understand how Hibernate does the ORM (Object-Relational Mapping) involved for JPA Entities.
Consider a simplified set of Entities for your order. Class
Ordercontains 2 fields:numberandcustomerIdand a list of order lines. ClassOrderLinecontainsproductCodeandquantityfields, as well as auidkey and a reference to the parent Order.These classes may be defined thus:
Now, if you performed the following JPQL query on these Entities:
then Hibernate performs this query as a ‘flattened’ SQL query similar to the following:
which would give a result like this:
which Hibernate would use to ‘reconstruct’
Orderobjects with attached lists ofOrderLinesub-objects.However, since the number of order lines per order is random, there is no way for Hibernate to know how many rows of this query to take to get the specified maximum number of
Orderobjects required. So it has to take the whole query and build up the objects in memory until it has the right amount, before discarding the rest of the result set. The log warning it produces alludes to this:We’re only just discovering now that these queries can have a significant impact on server memory use, and we’ve had issues with our server falling over with out of memory errors when these queries are attempted.
By the way, I will say now that this is mostly just theory on my part and I have no idea how the actual Hibernate code works. Most of this you can glean from the logs when you have Hibernate logging the SQL statements it generates.
UPDATE:
Recently I have discovered a little ‘gotcha’ with the above.
Consider a third Entity called
Shipmentwhich is for one or more Lines of an Order.The
Shipmententity would have a@ManyToOneassociation to theOrderentity.Let’s say you have 2 Shipments for the same Order which has 4 Lines.
If you perform a JPQL query for the following:
You would expect (or at least I did) to get 2 shipment objects back, each with a reference to the same Order object, which itself would contain the 4 Lines.
Nope, wrong again! In fact, you get 2 Shipment objects, each referring to the same Order object, which contains 8 Lines! Yes, the Lines get duplicated in the Order! And yes, that is even if you specify the DISTINCT clause.
If you research this issue here on SO or elsewhere (most notably the Hibernate forums), you’ll find that this is actually a feature not a bug, according to the Hibernate powers that be. Some people actually want this behaviour!
Go figure.