Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pagination with Hibernate criteria and FetchMode.JOIN

I've got two tables, 'Players' and 'Items'. Players have a list of items. I want to retrieve the players, and all of their items, using pagination. I want to paginate based on the players and without regard to how many items there are.

So I do something like this:

Criteria c = session.createCriteria(Players.class).setFetchMode("items", FetchMode.JOIN);
c.addOrder(Order.asc("playerID"));
c.setFirstResult(0);
c.setMaxResults(25);
List<Player> players = c.list();

Is this going to give me the first 25 players, or will it give me the first 25 items (grouped by players)? I'm wondering if this behavior is undefined like it would be for JPA queries, or if perhaps there's a guaranteed answer.

Regardless, what are Criteria queries that would give me the first 25 players or the first 25 player-item combinations (ordered by player ID, then item ID)?

like image 759
Brandon Yarbrough Avatar asked Jun 16 '11 00:06

Brandon Yarbrough


People also ask

How can we join multiple tables in Hibernate criteria?

Criteria in Hibernate can be used for join queries by joining multiple tables, useful methods for Hibernate criteria join are createAlias(), setFetchMode() and setProjection() Criteria in Hibernate API can be used for fetching results with conditions, useful methods are add() where we can add Restrictions.

What is the use of FetchMode lazy in Hibernate criteria?

FetchType. In general, FetchMode defines how Hibernate will fetch the data (by select, join or subselect). FetchType, on the other hand, defines whether Hibernate will load data eagerly or lazily.

What is criteria uniqueResult ()?

uniqueResult() Convenience method to return a single instance that matches the query, or null if the query returns no results. Method Detail.

What is the use of createAlias in Hibernate?

createAlias. Join an association using the specified join-type, assigning an alias to the joined association. The joinType is expected to be one of CriteriaSpecification.


2 Answers

From the "Advanced Problems" FAQ for Hibernate:

http://community.jboss.org/wiki/HibernateFAQ-AdvancedProblems

It should be also obvious why resultset row-based "limit" operations, such as setFirstResult(5) and setMaxResults(10) do not work with these kind of eager fetch queries. If you limit the resultset to a certain number of rows, you cut off data randomly. One day Hibernate might be smart enough to know that if you call setFirstResult() or setMaxResults() it should not use a join, but a second SQL SELECT. Try it, your version of Hibernate might already be smart enough. If not, write two queries, one for limiting stuff, the other for eager fetching.

In other words, Hibernate does not support this. If you were smarter and knew how Hibernate was implemented, it should have been obvious that setFirstResult and setMaxResults doesn't do anything remotely like pagination in all cases. It was so obvious that it does not need documenting.

like image 64
Brandon Yarbrough Avatar answered Nov 15 '22 06:11

Brandon Yarbrough


Quite sure, but not 100%, it will do the following:

It will join the players and the items, order by playerID and take the first 25 results, all in one SQL query. From this data, it creates the players and items, which will result in an arbitrary amount of players (less or equal then 25) with a total of 25 items. It may happen that the last player doesn't get all items.

To get 25 players, avoid FetchMode.JOIN (to avoid the N+1 problem, use batch-size in the mapping file):

List<Player> first25Players = session
  .createCriteria(Players.class)
  .addOrder(Order.asc("playerID"))
  .setMaxResults(25)
  .list();

To get 25 items, start the query by Item, not Player.

List<Item> first25Items = session
  .createCriteria(Item.class)
  .addOrder(Order.asc("player")) // assuming that player is available
  .setMaxResults(25)
  .list();

If there is no navigation from the item to the player, you may add one.

like image 25
Stefan Steinegger Avatar answered Nov 15 '22 05:11

Stefan Steinegger