-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: Pagination and generic Dao
PostPosted: Mon Mar 11, 2013 4:43 am 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
Hi,

I have a Generic Dao on some legacy source code and I would need to make it fit for pagination.

The number of rows are to be calculated based on the query where clause.

And the database server forces me to have a query statement free of any order by clause as it stands in the way of the counting of rows.

Also a query may have a specific projection.

The trouble is to calculate the number of returned rows.

At first I tried to have the final query, clone it and set the order by clause to null. But the Hibernate API refused me that.

Then I tried to create a new query by extracting the where clause from the passed in query. But the Hibernate API refused me that as well.

So now I'm trying to first calculate the number of rows and then add a projection and an order by clause if any.

Here is the Dao source code:
Code:
   public Page<T> getPage(final int pageNumber, final int pageSize, Criteria criteria, Projection projection, Order order) {
      int totalSize = 0;
      if (pageSize > 0) {
          criteria.setProjection(Projections.rowCount());
          // TODO Why is uniqueResult returning a Long and setFirstResult requiring an int ?
          totalSize = ((Long) criteria.uniqueResult()).intValue();
          int startIndex = Page.getStartIndex(pageNumber, pageSize, totalSize);
          criteria.setFirstResult(startIndex);
          criteria.setMaxResults(pageSize);
      }
        if (projection != null) {
            criteria.setProjection(projection);
        } else {
            criteria.setProjection(null);
        }
      if (order != null) {
          criteria.addOrder(order);
      }
      List<T> list = criteria.list();
      return new Page<T>(pageNumber, pageSize, totalSize, list);
   }


And then I could call it like:
Code:
Page<MailAddress> page = getPage(pageNumber, pageSize, criteria, order);


But the trouble is that there may be several order by clauses, like for example:
Code:
addOrder(Order.asc("firstname")).addOrder(Order.asc("lastname")).addOrder(Order.asc("email"));


So how can I have an argument to pass in several order by clauses ?

Kind Regards,


Top
 Profile  
 
 Post subject: Re: Pagination and generic Dao
PostPosted: Fri Mar 22, 2013 2:45 am 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
So I created an OrderList class which could hold a sorted series of order clauses.
Code:
public class OrderList {

    private List<Order> orders;
   
    public OrderList add(Order order) {
        if (orders == null) {
            orders = new ArrayList<Order>();           
        }
        orders.add(order);
        return this;
    }
   
    public List<Order> getOrders() {
        return orders;
    }
   
}


I can now create the orders list like:
Code:
        OrderList orderList = new OrderList().add(Order.asc("firstname")).add(Order.asc("lastname")).add(Order.asc("email"));


And pass it to the generic Dao method like:
Page<UserAccount> page = getPage(pageNumber, pageSize, criteria, orderList);

The generic Dao looks like:
Code:
   public Page<T> getPage(int pageNumber, int pageSize, Criteria criteria, Projection projection, OrderList orderList) {
      int totalSize = 0;
      if (pageSize > 0) {
          criteria.setProjection(Projections.rowCount());
          // TODO Why is uniqueResult returning a Long and setFirstResult requiring an int ?
          totalSize = ((Long) criteria.uniqueResult()).intValue();
          int startIndex = Page.getStartIndex(pageNumber, pageSize, totalSize);
          criteria.setFirstResult(startIndex);
          criteria.setMaxResults(pageSize);
      }
        if (projection != null) {
            criteria.setProjection(projection);
        } else {
            // Remove the count project
            criteria.setProjection(null);
            // Specify the main class as being the projection to avoid JOINed projections
            criteria.setResultTransformer(Criteria.ROOT_ENTITY);
        }
      if (orderList != null) {
          for(Order order : orderList.getOrders()) {
              criteria.addOrder(order);             
          }
      }
      List<T> list = criteria.list();
      return new Page<T>(pageNumber, pageSize, totalSize, list);
   }


In case there is a specific projection, then it is passed as well to the generic Dao method.

Some additional methods are provided for the different cases of using a projection and / or some order clause:
Code:
    @Override
    public Page<T> getPage(int pageNumber, int pageSize, Criteria criteria) {
        return getPage(pageNumber, pageSize, criteria, null, null);
    }
   
    @Override
    public Page<T> getPage(int pageNumber, int pageSize, Criteria criteria, Projection projection) {
        return getPage(pageNumber, pageSize, criteria, projection, null);
    }
   
    @Override
    public Page<T> getPage(int pageNumber, int pageSize, Criteria criteria, OrderList orderList) {
        return getPage(pageNumber, pageSize, criteria, null, orderList);
    }


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.