Friday, November 6, 2009

Hibernate Paging with Previous and Next

Usually in web applications we have to show some table or list of data to the user. Over time this data is growing. Most of the times, the amount is data is not too big. Therefore, in many cases, it is enough loading all the data to memory, then showing it to the user. But, there are time in which the amount of data is too big. Therefore, it wouldn't be wise loading all the data on the server, simply in order to show just a part of it. Hibernate gives us a neat way of partially loading data by supplying 2 methods for the Query class:

  • setFirstResult: This method sets the first result we would like to see in our our list. Suppose we are getting all photos of a user, by doing something like: “select user.photos from User user”. The user is currently having 1000 pictures, but we want to show pictures starting from the 100th picture. We can use setFirstResult to accomplish that task.
  • setMaxResults: This method sets the maximum results that will be returned by the query. For example, if we would like to return only 100 photos for our user, we would do something like: query.setMaxResults(100).

As we can see we can use setFirstResult and setMaxResults to control which part of our list will be actually returned by the query. Of course, that Hibernate utilizes the specific dialect of the database server we are using to efficiently accomplish the task of fetching only a portion of the data.

We would like to use these 2 hibernate methods to construct paging effect in Hibernate. By saying “paging” we mean, that we would like to give Hibernate 2 parameters: in which page we are, and what is the size of our page. In return we would like to receive the items in that specific page. Accomplishing this task in Hibernate is quite easy and can be done by using simple math on the page and page size parameters. For example, if we would like Hibernate to return items in page 5 and in each page we would like to show 20 items, we can do:

query.setFirstResult(5 * 20).setMaxResults(20).list();

or in more general form:

query.setFirstResult(page * pageSize).setMaxResults(pageSize).list();

Showing the items for a specific page isn’t enough. We also would like to be able to tell if in a specific page there are more items. This will allow us to add “Next” button on out user interface. The trick to know if there is a next page, it to get one more additional item. If there is such item, we can know that there is a next page. This trick costs us in getting only one more item and therefore is pretty efficient in terms of performance. So, the general form for getting items shown above can be changed to:

query.setFirstResult(page * pageSize).setMaxResults(pageSize + 1).list();

Let’s take a look at a class named PagedResults, that gets an Hibernate query, page number, page size and in return gives us list of items according to the desired page and page size, and 2 more methods: isNextPage, isPreviousPage, that gives us indication if there are more pages or if we are at the first page:

package com.bashan.blog.persistence;
import org.hibernate.Query;
import java.util.List;
public class PagedResults {
  private List results;
  private int pageSize;
  private int page;
  public PagedResults(Query query, int page, int pageSize) {
    this.page = page;
    this.pageSize = pageSize;
    results = query.setFirstResult(page * pageSize).setMaxResults(pageSize + 1).list();
  }
  public boolean isNextPage() {
    return results.size() > pageSize;
  }
  public boolean isPreviousPage() {
    return page > 0;
  }
  public List getList() {
    return isNextPage() ?
        results.subList(0, pageSize) : results;
  }
}

Note that the method getList returns sub list of the original list. That is because the original list may return one additional item that we use only to know if there is a next page. We don’t want to show this item on our user interface.

No comments:

Post a Comment