使用HibernateTemplate的findByNamedParam函数进行分页

时间:2011-02-25 00:23:06

标签: java hibernate spring

我见过很多关于如何使用一些非常简单的查询创建分页的示例。但我没有看到任何使用HibernateTemplate的findByNamedParam方法。

如何在使用findByNamedParam方法的同时设置查询的firstResult和maxResult参数?

基本上,我正在尝试通过HibernateTemplate的findByNamedParam方法为我正在创建的hql查询添加分页。

2 个答案:

答案 0 :(得分:5)

经过大量研究后,我终于得到了我想要的东西。

首先,需要创建一个HibernateCallback实现:

HibernateCallbackImpl.java:

import java.sql.SQLException;
import java.util.List;

import org.apache.poi.hssf.record.formula.functions.T;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;

public class HibernateCallbackImpl 
    implements HibernateCallback<List<T>> {

    private String queryString;
    private String[] paramNames;
    private Object[] values;

    private int firstResult;
    private int maxResults;

    /**
     * Fetches a {@link List} of entities from the database using pagination.
     * Execute HQL query, binding a number of values to ":" named parameters in the query string.
     * 
     * @param queryString a query expressed in Hibernate's query language
     * @param paramNames the names of the parameters
     * @param values the values of the parameters 
     * @param firstResult a row number, numbered from 0
     * @param maxResults the maximum number of rows
     */
    public HibernateCallbackImpl(
            String queryString, 
            String[] paramNames, 
            Object[] values,
            int firstResult,
            int maxResults) {
        this.queryString = queryString;
        this.paramNames = paramNames;
        this.values = values;

        this.firstResult = firstResult;
        this.maxResults = maxResults;
    }

    @Override
    public List<T> doInHibernate(Session session) throws HibernateException,
            SQLException {
        Query query = session.createQuery(queryString);
        query.setFirstResult(firstResult);
        query.setMaxResults(maxResults);

        // TODO: throw proper exception when paramNames.length != values.length

        for (int c=0; c<paramNames.length; c++) {
            query.setParameter(paramNames[c], values[c]);
        }

        @SuppressWarnings("unchecked")
        List<T> result = query.list();

        return result;
    }

}

然后,我可以实例化新对象,它将返回我想要的内容:

示例:

@SuppressWarnings("unchecked")
List<TitleProductAccountApproval> tpaas = 
    getHibernateTemplate().executeFind(
        new HibernateCallbackImpl(
            hql.toString(), 
            paramNames.toArray(new String[paramNames.size()]), 
            values.toArray(),
            firstResult,
            maxResult
        )
    );

答案 1 :(得分:4)

@Corey的解决方案效果很好但它包含了for循环中调用query.setParameter(...)的问题。

问题是它没有考虑集合或数组的参数,这将导致我们的ClassCastExceptions,因为Hibernate试图通过调用集合或数组上的getId()来确定ID(这是错误的)。这发生在例如如果您正在使用IN子句(例如...... WHERE部门IN(:departments)...)其中'departments'是一个数组或部门实体的集合。

这是因为集合或数组需要使用'query.setParameterList(paramName,(Object [])value)'或'query.setParameterList(paramName,(Collection)value)'

长话短说:

我通过添加“applyNamedParameterToQuery()”方法,该方法我从org.springframework.orm.hibernate3.HibernateTemplate.applyNamedParameterToQuery(查询,字符串,对象)借由改性的@Corey版本

import java.sql.SQLException;
import java.util.List;

import org.apache.poi.hssf.record.formula.functions.T;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;

public class HibernateCallbackImpl 
    implements HibernateCallback<List<T>> {

    private String queryString;
    private String[] paramNames;
    private Object[] values;

    private int firstResult;
    private int maxResults;

    /**
     * Fetches a {@link List} of entities from the database using pagination.
     * Execute HQL query, binding a number of values to ":" named parameters in the query string.
     * 
     * @param queryString a query expressed in Hibernate's query language
     * @param paramNames the names of the parameters
     * @param values the values of the parameters 
     * @param firstResult a row number, numbered from 0
     * @param maxResults the maximum number of rows
     */
    public HibernateCallbackImpl(
            String queryString, 
            String[] paramNames, 
            Object[] values,
            int firstResult,
            int maxResults) {
        this.queryString = queryString;
        this.paramNames = paramNames;
        this.values = values;

        this.firstResult = firstResult;
        this.maxResults = maxResults;
    }

    @Override
    public List<T> doInHibernate(Session session) throws HibernateException,
            SQLException {
        Query query = session.createQuery(queryString);
        query.setFirstResult(firstResult);
        query.setMaxResults(maxResults);

        // TODO: throw proper exception when paramNames.length != values.length

        for (int c=0; c<paramNames.length; c++) {
            applyNamedParameterToQuery(query, paramNames[c], values[c]);
        }

        @SuppressWarnings("unchecked")
        List<T> result = query.list();

        return result;
    }


     /**
     * Code borrowed from org.springframework.orm.hibernate3.HibernateTemplate.applyNamedParameterToQuery(Query, String, Object)
     * 
     * Apply the given name parameter to the given Query object.
     * @param queryObject the Query object
     * @param paramName the name of the parameter
     * @param value the value of the parameter
     * @throws HibernateException if thrown by the Query object
     */
    protected void applyNamedParameterToQuery(Query queryObject, String paramName, Object value)
            throws HibernateException {

        if (value instanceof Collection) {
            queryObject.setParameterList(paramName, (Collection) value);
        }
        else if (value instanceof Object[]) {
            queryObject.setParameterList(paramName, (Object[]) value);
        }
        else {
            queryObject.setParameter(paramName, value);
        }
    }

}