Just had an interesting discussion on ejb3-feedback@sun.com, started by David Cherryhomes, which saw me stupidly insistingthat something can't be done when in fact, now that I think about it, /I realize I've actually done it before/, and that even the Hibernate AdminApp example uses this pattern!
So, just so I don't forget this pattern again, I'm going to write it down, and also write a reuseable class implementing it.
The basic problem is pagination. I want to display next
and previous
buttons to the user, but disable them if there are
no more, or no previous query results. But I don't want to retrieve all the query results in each request, or execute a
separate query to count them. So, here's the correct approach:
public class Page { private List results; private int pageSize; private int page; public Page(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-1) : results; } }
You can return this object to your JSP, and use it in Struts, WebWork or JSTL tags. Getting a page in your persistence logic is as simple as:
public Page getPosts(int page) { return new Page( session.createQuery("from Posts p order by p.date desc") page, 40 ); }
The Page class works in both Hibernate and EJB 3.0.