开发者

Pagination with Hibernate criteria and FetchMode.JOIN

开发者 https://www.devze.com 2023-03-13 18:52 出处:网络
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 withou

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(开发者_StackOverflowOrder.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)?


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消