com.abssh.util.GenericDao.java Source code

Java tutorial

Introduction

Here is the source code for com.abssh.util.GenericDao.java

Source

/**
 * Copyright (c) 2010 www.pub.cn
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * 
 * $Id: GenericDao.java,v 1.6 2010/08/22 07:11:03 xp Exp $
 */
package com.abssh.util;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.internal.CriteriaImpl;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.transform.Transformers;
import org.springframework.util.Assert;

import com.abssh.util.Page;
import com.abssh.util.PropertyFilter;
import com.abssh.util.PropertyFilter.MatchType;
import com.abssh.util.ReflectionUtils;

/**
 * ???Dao.
 * 
 * ,?. ?Service,?DAO?,?.
 * 
 * @param <T>
 *            DAO?
 * @param <PK>
 *            
 * 
 * @author pub
 * 
 */

public class GenericDao<T, PK extends Serializable> extends SimpleHibernateDao<T, PK> implements Serializable {

    private static final long serialVersionUID = 64398323349897817L;

    private static String DEF_SEPARATOR = ".";// 

    /**
     * Dao?. ??Class.
     * 
     * <br/>
     * eg. public class UserDao extends GenericDao<User, Long>{ }
     */
    public GenericDao() {
        super();
    }

    /**
     * ?Dao, ServiceGenericDao. Class.
     * 
     * <br/>
     * eg. GenericDao<User, Long> userDao = new GenericDao<User,
     * Long>(sessionFactory, User.class);
     */
    public GenericDao(final SessionFactory sessionFactory, final Class<T> entityClass) {
        super(sessionFactory, entityClass);
    }

    /**
     * ?page?null.
     */
    public Page<T> getAll(final Page<T> page) {
        return findPage(page);
    }

    private boolean matchOrderClause(String hql) {
        String regEx = "(?i)\\s+order(\\s+)by\\s+";
        Pattern p = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
        Matcher m = p.matcher(hql);

        return m.find();
    }

    private String getOrderClause(Page<T> page, String hql) {
        StringBuffer orderByClause = new StringBuffer();

        if ((!matchOrderClause(hql)) && page.isOrderBySetted()) {
            orderByClause.append(" order by ");

            String[] orderByArray = StringUtils.split(page.getOrderBy(), ',');
            String[] orderArray = StringUtils.split(page.getOrder(), ',');
            Assert.isTrue(orderByArray.length == orderArray.length, "orderBy and order is not suited!");

            for (int i = 0; i < orderByArray.length; i++) {
                orderByClause.append(orderByArray[i]).append(" ").append(orderArray[i]);
                if (i != orderByArray.length - 1) {
                    orderByClause.append(",");
                }
            }
        }

        return orderByClause.toString();
    }

    /**
     * HQLhqlorder by
     * 
     * @param page
     *            ??null
     * @param hql
     *            hql??order bypageorder by.
     * @param params
     *            ????,?.
     * 
     * @return , ??.
     */
    @SuppressWarnings("unchecked")
    public Page<T> findPage(final Page<T> page, final String hql, final Object... params) {
        Assert.notNull(page, "page should not be null!");

        Query q = createQuery(hql + getOrderClause(page, hql), params);

        if (page.isAutoCount()) {
            long totalCount = countHqlResult(hql, params);
            page.setTotalCount(totalCount);
        }
        if (page != null && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameter(q, page);
        page.setResult(q.list());
        return page;
    }

    /**
     * HQL.
     * 
     * @param page
     *            ??null
     * @param hql
     *            hql?.
     * @param values
     *            ???,??.
     * 
     * @return , ??.
     */
    @SuppressWarnings("unchecked")
    public Page<T> findPage(final Page<T> page, final String hql, final Map<String, Object> values) {
        Assert.notNull(page, "page should not be null!");

        Query q = createQuery(hql + getOrderClause(page, hql), values);

        if (page.getPageSize() > 0 && page.isAutoCount()) {
            long totalCount = countHqlResult(hql, values);
            page.setTotalCount(totalCount);
        }
        if (page != null && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameter(q, page);

        List result = q.list();
        page.setResult(result);
        return page;
    }

    /**
     * ??hql?
     * 
     * @author zhirong
     * @param page
     * @param sql
     *            ?HQL?
     * @param countSql
     *            HQL?
     * @param params
     * @return
     */
    @SuppressWarnings("unchecked")
    public Page<T> findPage(final Page<T> page, final String hql, String countHql, final Object... params) {
        Assert.notNull(page, "page should not be null!");

        Query q = createQuery(hql + getOrderClause(page, hql), params);

        if (page.isAutoCount()) {
            long totalCount = countHqlResult(countHql, params);
            page.setTotalCount(totalCount);
        }
        if (page != null && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameter(q, page);
        page.setResult(q.list());
        return page;
    }

    /**
     * ??hql?
     * 
     * @author zhirong
     * @param page
     * @param sql
     *            ?HQL?
     * @param countSql
     *            HQL?
     * @param params
     * @return
     */
    @SuppressWarnings("unchecked")
    public Page<T> findPage(final Page<T> page, final String hql, String countHql,
            final Map<String, Object> values) {
        Assert.notNull(page, "page should not be null!");

        Query q = createQuery(hql + getOrderClause(page, hql), values);

        if (page.getPageSize() > 0 && page.isAutoCount()) {
            long totalCount = countHqlResult(hql, values);
            page.setTotalCount(totalCount);
        }
        if (page != null && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameter(q, page);

        List result = q.list();
        page.setResult(result);
        return page;
    }

    /**
     * SQLsqlorder by
     * 
     * @author zhirong
     * @param page
     *            ??null
     * @param sql
     *            sql??order bypageorder by.
     * @param params
     *            ????,?.
     * 
     * @return , ??.
     */
    @SuppressWarnings("unchecked")
    public Page<T> findPageSQL(final Page<T> page, final String sql, final Object... params) {
        Assert.notNull(page, "page should not be null!");

        Query q = createSQLQuery(sql + getOrderClause(page, sql), params).addEntity(entityClass);

        if (page.isAutoCount()) {
            long totalCount = countSqlResult(sql, params);
            page.setTotalCount(totalCount);
        }
        if (page != null && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameter(q, page);
        page.setResult(q.list());
        return page;
    }

    /**
     * SQL.
     * 
     * @author zhirong
     * @param page
     *            ??null
     * @param sql
     *            sql?.
     * @param values
     *            ???,??.
     * 
     * @return , ??.
     */
    @SuppressWarnings("unchecked")
    public Page<T> findPageSQL(final Page<T> page, final String sql, final Map<String, Object> values) {
        Assert.notNull(page, "page should not be null!");

        Query q = createSQLQuery(sql + getOrderClause(page, sql), values).addEntity(entityClass);

        if (page.getPageSize() > 0 && page.isAutoCount()) {
            long totalCount = countSqlResult(sql, values);
            page.setTotalCount(totalCount);
        }
        if (page != null && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameter(q, page);

        List result = q.list();
        page.setResult(result);
        return page;
    }

    /**
     * SQL.
     * 
     * @author zhirong
     * @param page
     *            ??null
     * @param sql
     *            sql?.
     * @param values
     *            ???,??.
     * 
     * @return , ??.
     */
    @SuppressWarnings("unchecked")
    public Page<T> findPageSQLNonHibernateEntity(final Page<T> page, final String sql,
            final Map<String, Object> values) {
        Assert.notNull(page, "page should not be null!");

        String order = getOrderClause(page, sql);
        String selectSQL = sql + order;
        Query q = createSQLQuery(selectSQL, values).setResultTransformer(Transformers.aliasToBean(entityClass));

        if (page.getPageSize() > 0 && page.isAutoCount()) {
            long totalCount = countSqlResult(sql, values);
            page.setTotalCount(totalCount);
        }
        if (page != null && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameter(q, page);

        List result = q.list();
        page.setResult(result);
        return page;
    }

    /**
     * SQL.
     * 
     * @author zhirong
     * @param <M>
     * @param page
     *            ??null
     * @param sql
     *            sql?.
     * @param values
     *            ???,??.
     * 
     * @return , ??.
     */
    @SuppressWarnings("unchecked")
    public Page<Map> findPageSQLNonHibernateMap(final Page<Map> page, final String sql,
            final Map<String, Object> values) {
        Assert.notNull(page, "page should not be null!");

        Query q = createSQLQuery(sql, values).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);

        if (page.getPageSize() > 0 && page.isAutoCount()) {
            long totalCount = countSqlResult(sql, values);
            page.setTotalCount(totalCount);
        }
        if (page != null && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameterMap(q, page);

        List result = q.list();
        page.setResult(result);
        return page;
    }

    /**
     * SQL?.
     * 
     * @author zhirong
     * @param values
     *            ????,?.
     */
    @SuppressWarnings("unchecked")
    public List<Map<String, Object>> findSQL(final String sql, final Map<String, String> searchParam) {
        return (List<Map<String, Object>>) createSQLQuery(sql, searchParam)
                .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
    }

    /**
     * SQL?.
     * 
     * @author zhirong
     * @param values
     *            ????,?.
     */
    @SuppressWarnings("unchecked")
    public List<Map<String, Object>> findSQL(final String sql) {
        return (List<Map<String, Object>>) createSQLQuery(sql)
                .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
    }

    /**
     * ??sql?
     * 
     * @author zhirong
     * @param page
     * @param sql
     *            ?SQL?
     * @param countSql
     *            SQL?
     * @param params
     * @return
     */
    @SuppressWarnings("unchecked")
    public Page<T> findPageSQL(final Page<T> page, final String sql, String countSql, final Object... params) {
        Assert.notNull(page, "page should not be null!");

        Query q = createSQLQuery(sql + getOrderClause(page, sql), params).addEntity(entityClass);

        if (page.isAutoCount()) {
            long totalCount = countSqlResult(countSql, params);
            page.setTotalCount(totalCount);
        }
        if (page != null && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameter(q, page);
        page.setResult(q.list());
        return page;
    }

    /**
     * ??sql?
     * 
     * @author zhirong
     * @param page
     * @param sql
     *            ?SQL?
     * @param countSql
     *            SQL?
     * @param values
     * @return
     */
    @SuppressWarnings("unchecked")
    public Page<T> findPageSQL(final Page<T> page, final String sql, String countSql,
            final Map<String, Object> values) {
        Assert.notNull(page, "page should not be null!");

        Query q = createSQLQuery(sql + getOrderClause(page, sql), values).addEntity(entityClass);

        if (page.getPageSize() > 0 && page.isAutoCount()) {
            long totalCount = countSqlResult(countSql, values);
            page.setTotalCount(totalCount);
        }
        if (page != null && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameter(q, page);

        List result = q.list();
        page.setResult(result);
        return page;
    }

    /**
     * Criteria.
     * 
     * @param page
     *            ??null.
     * @param criterions
     *            ???Criterion.
     * 
     * @return .??.
     */
    @SuppressWarnings("unchecked")
    public Page<T> findPage(final Page<T> page, final Criterion... criterions) {
        Assert.notNull(page, "page should not be null!");

        Criteria c = createCriteria(criterions);

        if (page.isAutoCount()) {
            int totalCount = countCriteriaResult(c);
            page.setTotalCount(totalCount);
        }
        if (page != null && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameter(c, page);
        List result = c.list();
        page.setResult(result);
        return page;
    }

    /**
     * Criteria.
     * 
     * @author zhangxy
     * @param page
     *            ??null.
     * @param Criteria
     *            Criteria
     * @return .??.
     */
    @SuppressWarnings("unchecked")
    public Page<T> findPage(final Page<T> page, Criteria c) {
        Assert.notNull(page, "page should not be null!");

        if (page.isAutoCount()) {
            int totalCount = countCriteriaResult(c);
            page.setTotalCount(totalCount);
        }
        if (page != null && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameter(c, page);
        List result = c.list();
        page.setResult(result);
        return page;
    }

    /**
     * @NamedQuery
     * 
     * @param page
     * @param queryName
     *            ??
     * @param params
     * @return
     */
    @SuppressWarnings("unchecked")
    public Page<T> namedFindPage(final Page<T> page, final String queryName, final Object... params) {
        Assert.notNull(page, "page should not be null!");

        String hql = getNamedQuery(queryName).getQueryString();
        Query q = createQuery(hql + getOrderClause(page, hql), params);

        if (page.getPageSize() > 0 && page.isAutoCount()) {
            long totalCount = countHqlResult(hql, params);
            page.setTotalCount(totalCount);
        }
        if (null != page && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameter(q, page);

        List result = q.list();
        page.setResult(result);
        return page;
    }

    /**
     * @NamedQuery
     * 
     * @param page
     * @param queryName
     *            ??
     * @param values
     * @return
     */
    @SuppressWarnings("unchecked")
    public Page<T> namedFindPage(final Page<T> page, final String queryName, final Map<String, Object> values) {
        Assert.notNull(page, "page should not be null!");

        String hql = getNamedQuery(queryName, values).getQueryString();
        Query q = createQuery(hql + getOrderClause(page, hql), values);

        if (page.getPageSize() > 0 && page.isAutoCount()) {
            long totalCount = countHqlResult(hql, values);
            page.setTotalCount(totalCount);
        }
        if (null != page && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameter(q, page);

        List result = q.list();
        page.setResult(result);
        return page;
    }

    /**
     * @NamedNativeQuery
     * 
     * @param page
     * @param queryName
     *            ??
     * @param params
     * @return
     */
    @SuppressWarnings("unchecked")
    public Page<T> namedNativeFindPage(final Page<T> page, final String queryName, final Object... params) {
        Assert.notNull(page, "page should not be null!");

        String sql = getNamedQuery(queryName).getQueryString();
        Query q = createSQLQuery(sql + getOrderClause(page, sql), params).addEntity(entityClass);

        if (page.getPageSize() > 0 && page.isAutoCount()) {
            long totalCount = countSqlResult(sql, params);
            page.setTotalCount(totalCount);
        }
        if (null != page && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameter(q, page);

        List result = q.list();
        page.setResult(result);
        return page;
    }

    /**
     * @NamedNativeQuery
     * 
     * @param page
     * @param queryName
     *            ??
     * @param values
     * @return
     */
    @SuppressWarnings("unchecked")
    public Page<T> namedNativeFindPage(final Page<T> page, final String queryName,
            final Map<String, Object> values) {
        Assert.notNull(page, "page should not be null!");

        String sql = getNamedQuery(queryName, values).getQueryString();
        Query q = createSQLQuery(sql + getOrderClause(page, sql), values).addEntity(entityClass);

        if (page.getPageSize() > 0 && page.isAutoCount()) {
            long totalCount = countSqlResult(sql, values);
            page.setTotalCount(totalCount);
        }
        if (null != page && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameter(q, page);

        List result = q.list();
        page.setResult(result);
        return page;
    }

    /**
     * ?Query,.
     */
    protected Query setPageParameter(final Query q, final Page<T> page) {
        // hibernatefirstResult??0
        if (page.getPageSize() > 0) {
            q.setFirstResult(page.getFirst() - 1);
            q.setMaxResults(page.getPageSize());
        }
        return q;
    }

    /**
     * ?Query,.
     */
    protected Query setPageParameterMap(final Query q, final Page<?> page) {
        // hibernatefirstResult??0
        if (page.getPageSize() > 0) {
            q.setFirstResult(page.getFirst() - 1);
            q.setMaxResults(page.getPageSize());
        }
        return q;
    }

    /**
     * ?Criteria,.
     */
    protected Criteria setPageParameter(final Criteria c, final Page<T> page) {
        // hibernatefirstResult??0
        if (page.getPageSize() > 0) {
            c.setFirstResult(page.getFirst() - 1);
            c.setMaxResults(page.getPageSize());
        }

        if (page.isOrderBySetted()) {
            String[] orderByArray = StringUtils.split(page.getOrderBy(), ',');
            String[] orderArray = StringUtils.split(page.getOrder(), ',');

            Assert.isTrue(orderByArray.length == orderArray.length, "orderBy and order is not suited!");

            for (int i = 0; i < orderByArray.length; i++) {
                if (Page.ASC.equals(orderArray[i])) {
                    c.addOrder(Order.asc(orderByArray[i]));
                } else {
                    c.addOrder(Order.desc(orderByArray[i]));
                }
            }
        }
        return c;
    }

    /**
     * countHql.hql??select count(*)?
     * 
     * <br/>
     * ???hql?,??hql?count?.
     */
    protected long countHqlResult(final String hql, final Object... params) {
        String fromHql = hql;
        // select??order by???count,?.
        fromHql = "from " + StringUtils.substringAfter(fromHql, "from");
        if (fromHql.indexOf("order by") > 0) {
            fromHql = StringUtils.substringBefore(fromHql, "order by");
        }

        String countHql = "select count(*) " + fromHql;

        try {
            Long count = findUnique(countHql, params);
            return count;
        } catch (Exception e) {
            throw new RuntimeException("can't auto count,hql is:" + countHql, e);
        }
    }

    /**
     * countHql.hql??select count(*)?
     * 
     * ???hql?,??hql?count?.
     */
    protected long countHqlResult(final String hql, final Map<String, Object> values) {
        String fromHql = hql;
        // select??order by???count,?.
        fromHql = "from " + StringUtils.substringAfter(fromHql, "from");
        if (fromHql.indexOf("order by") > 0) {
            fromHql = StringUtils.substringBefore(fromHql, "order by");
        }

        String countHql = "select count(*) " + fromHql;

        try {
            Long count = findUnique(countHql, values);
            return count;
        } catch (Exception e) {
            throw new RuntimeException("can't auto count,hql is:" + countHql, e);
        }
    }

    /**
     * countSQL.hql??select count(*)?
     * 
     * <br/>
     * ???sql?,??sql?count?.
     * 
     * @author zhirong
     */
    protected long countSqlResult(final String sql, final Object... params) {
        String fromSql = sql;
        // select??order by???count,?.
        fromSql = "from " + StringUtils.substringAfter(fromSql, "from");
        if (fromSql.indexOf("order by") > 0) {
            fromSql = StringUtils.substringBefore(fromSql, "order by");
        }

        String countSql = "select count(*) " + fromSql;

        try {
            Long count = null;
            Object obj = findUniqueSQL(countSql, params);
            if (obj instanceof BigInteger) {
                count = ((BigInteger) obj).longValue();
            } else if (obj instanceof BigDecimal) {
                count = ((BigDecimal) obj).longValue();
            }
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("can't auto count,sql is:" + countSql, e);
        }
    }

    /**
     * countSQL.hql??select count(*)?
     * 
     * <br/>
     * ???sql?,??sql?count?.
     * 
     * @author zhirong
     */
    protected long countSqlResult(final String sql, final Map<String, Object> values) {
        String fromSql = sql;
        // select??order by???count,?.
        // ====================================================??Distinct?SQL?
        // fromSql = "from " + StringUtils.substringAfter(fromSql, "from");
        // if (fromSql.indexOf("order by") > 0) {
        // fromSql = StringUtils.substringBefore(fromSql, "order by");
        // }
        // ==============================================================
        String countSql = "select count(*) from (" + fromSql + ")";

        try {
            Long count = ((BigDecimal) findUniqueSQL(countSql, values)).longValue();
            return count;
        } catch (Exception e) {
            throw new RuntimeException("can't auto count,sql is:" + countSql, e);
        }
    }

    /**
     * countCriteria.
     */
    @SuppressWarnings("unchecked")
    protected int countCriteriaResult(final Criteria c) {
        CriteriaImpl impl = (CriteriaImpl) c;

        // Projection?ResultTransformer?OrderBy??,??Count?
        Projection projection = impl.getProjection();
        ResultTransformer transformer = impl.getResultTransformer();

        List<CriteriaImpl.OrderEntry> orderEntries = null;
        try {
            orderEntries = (List) ReflectionUtils.getFieldValue(impl, "orderEntries");
            ReflectionUtils.setFieldValue(impl, "orderEntries", new ArrayList());
        } catch (Exception e) {
            logger.error("can not throw Exception:{}", e.getMessage());
        }

        // Count
        Long ct = (Long) c.setProjection(Projections.rowCount()).uniqueResult();
        int totalCount = ct == null ? 0 : ct.intValue();

        // ?Projection,ResultTransformerOrderBy??
        c.setProjection(projection);

        if (projection == null) {
            c.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
        }
        if (transformer != null) {
            c.setResultTransformer(transformer);
        }
        try {
            ReflectionUtils.setFieldValue(impl, "orderEntries", orderEntries);
        } catch (Exception e) {
            logger.error("can not throw Exception:{}", e.getMessage());
        }

        return totalCount;
    }

    /**
     * countCriteria.
     */
    @SuppressWarnings("unchecked")
    protected int sumCriteriaResult(final String propertyName, final Criteria c) {
        CriteriaImpl impl = (CriteriaImpl) c;

        // Projection?ResultTransformer?OrderBy??,??Sum?
        Projection projection = impl.getProjection();
        ResultTransformer transformer = impl.getResultTransformer();

        List<CriteriaImpl.OrderEntry> orderEntries = null;
        try {
            orderEntries = (List) ReflectionUtils.getFieldValue(impl, "orderEntries");
            ReflectionUtils.setFieldValue(impl, "orderEntries", new ArrayList());
        } catch (Exception e) {
            logger.error("can not throw Exception:{}", e.getMessage());
        }

        // Sum
        Integer sum = (Integer) c.setProjection(Projections.sum(propertyName)).uniqueResult();

        // ?Projection,ResultTransformerOrderBy??
        c.setProjection(projection);

        if (projection == null) {
            c.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
        }
        if (transformer != null) {
            c.setResultTransformer(transformer);
        }
        try {
            ReflectionUtils.setFieldValue(impl, "orderEntries", orderEntries);
        } catch (Exception e) {
            logger.error("can not throw Exception:{}", e.getMessage());
        }

        return sum == null ? 0 : sum;
    }

    // -- ?(PropertyFilter) --//

    /**
     * ,????.
     * 
     * @param matchType
     *            ??,????PropertyFilterMatcheType enum.
     */
    public List<T> findBy(final String propertyName, final Object value, final MatchType matchType) {
        Criterion criterion = buildPropertyFilterCriterion(propertyName, new Object[] { value }, matchType);
        return find(criterion);
    }

    public int sum(String propertyName, List<PropertyFilter> filters) {
        Criteria criteria = getSession().createCriteria(entityClass);
        Map<String, Criteria> criteriaMap = new HashMap<String, Criteria>();
        for (PropertyFilter filter : filters) {
            if (!filter.isMultiProperty()) {
                String propName = filter.getPropertyName();
                Object[] propertyValue = filter.getPropertyValue();
                MatchType matchType = filter.getMatchType();
                Criteria parent = findParentCriteria(criteria, propName, criteriaMap);
                String[] tmp = StringUtils.split(propName, DEF_SEPARATOR);
                parent.add(getCriterion(tmp[tmp.length - 1], propertyValue, matchType));
            } else {
                Disjunction disjunction = Restrictions.disjunction();
                Object[] propertyValue = filter.getPropertyValue();
                MatchType matchType = filter.getMatchType();
                for (String propName : filter.getPropertyNames()) {
                    Criteria parent = findParentCriteria(criteria, propName, criteriaMap);
                    String[] tmp = StringUtils.split(propName, DEF_SEPARATOR);
                    parent.add(getCriterion(tmp[tmp.length - 1], propertyValue, matchType));
                }
                criteria.add(disjunction);
            }
        }
        return sumCriteriaResult(propertyName, criteria);
    }

    public int count(List<PropertyFilter> filters) {
        Criteria criteria = getSession().createCriteria(entityClass);
        Map<String, Criteria> criteriaMap = new HashMap<String, Criteria>();
        for (PropertyFilter filter : filters) {
            if (!filter.isMultiProperty()) {
                String propName = filter.getPropertyName();
                Object[] propertyValue = filter.getPropertyValue();
                MatchType matchType = filter.getMatchType();
                Criteria parent = findParentCriteria(criteria, propName, criteriaMap);
                String[] tmp = StringUtils.split(propName, DEF_SEPARATOR);
                parent.add(getCriterion(tmp[tmp.length - 1], propertyValue, matchType));
            } else {
                Disjunction disjunction = Restrictions.disjunction();
                Object[] propertyValue = filter.getPropertyValue();
                MatchType matchType = filter.getMatchType();
                for (String propName : filter.getPropertyNames()) {
                    Criteria parent = findParentCriteria(criteria, propName, criteriaMap);
                    String[] tmp = StringUtils.split(propName, DEF_SEPARATOR);
                    parent.add(getCriterion(tmp[tmp.length - 1], propertyValue, matchType));
                }
                criteria.add(disjunction);
            }
        }
        return countCriteriaResult(criteria);
    }

    /**
     * ?.
     */
    @SuppressWarnings("unchecked")
    public List<T> find(List<PropertyFilter> filters) {
        Criteria criteria = getSession().createCriteria(entityClass);
        Map<String, Criteria> criteriaMap = new HashMap<String, Criteria>();
        for (PropertyFilter filter : filters) {
            if (!filter.isMultiProperty()) {
                String propertyName = filter.getPropertyName();
                Object[] propertyValue = filter.getPropertyValue();
                MatchType matchType = filter.getMatchType();
                Criteria parent = findParentCriteria(criteria, propertyName, criteriaMap);
                String[] tmp = StringUtils.split(propertyName, DEF_SEPARATOR);
                parent.add(getCriterion(tmp[tmp.length - 1], propertyValue, matchType));
            } else {
                Disjunction disjunction = Restrictions.disjunction();
                Object[] propertyValue = filter.getPropertyValue();
                MatchType matchType = filter.getMatchType();
                for (String propertyName : filter.getPropertyNames()) {
                    Criteria parent = findParentCriteria(criteria, propertyName, criteriaMap);
                    String[] tmp = StringUtils.split(propertyName, DEF_SEPARATOR);
                    parent.add(getCriterion(tmp[tmp.length - 1], propertyValue, matchType));
                }
                criteria.add(disjunction);
            }
        }
        return criteria.list();
    }

    /**
     * SQL (=?)
     * 
     * @param sql
     *            SQL
     * @param param
     *            ?
     * @return ??object
     */
    @SuppressWarnings("unchecked")
    public List findList(String sql, Object... param) {
        SQLQuery query = getSession().createSQLQuery(sql);
        if (param != null && param.length > 0) {
            for (int i = 0; i < param.length; i++) {
                query.setParameter(i, param[i]);
            }
        }
        return query.list();
    }

    /**
     * SQL (=:property)
     * 
     * @param sql
     *            SQL
     * @param values
     *            ?
     * @return ??object
     */
    @SuppressWarnings("unchecked")
    public List findListByProperty(String sql, final Map<String, Object> values) {
        SQLQuery query = getSession().createSQLQuery(sql);
        if (values != null && values.size() > 0) {
            query.setProperties(values);
        }
        return query.list();
    }

    /**
     * ?SQL
     * 
     * @param pageSize
     *            ??,0?
     * @param pageNo
     *            ??1?
     * @param sql
     *            SQL
     * @param param
     *            ?
     * @return ??object
     */
    @SuppressWarnings("unchecked")
    public List findList(int pageSize, int pageNo, String sql, Object... param) {
        if (pageSize <= 0 || pageNo <= 0) {
            // ?
            return findList(sql, param);
        }
        SQLQuery query = getSession().createSQLQuery(sql);
        query.setFirstResult(((pageNo - 1) * pageSize));
        query.setMaxResults(pageSize);
        if (param != null && param.length > 0) {
            for (int i = 0; i < param.length; i++) {
                query.setParameter(i, param[i]);
            }
        }
        return query.list();
    }

    /**
     * SQL
     * 
     * @param sql
     *            : SQL
     * @param clazz
     *            ?list
     * @param param
     *             ?
     * @return 
     */
    @SuppressWarnings("unchecked")
    public List findList(String sql, Class clazz, Object... param) {
        Query query = getSession().createSQLQuery(sql).addEntity(clazz);
        if (param != null && param.length > 0) {
            for (int i = 0; i < param.length; i++) {
                query.setParameter(i, param[i]);
            }
        }
        return query.list();
    }

    /**
     * SQL
     * 
     * @param pageSize
     *            ??,0?
     * @param pageNo
     *            ??1?
     * @param sql
     *            SQL
     * @param clazz
     *            ?list
     * @param param
     *            ?
     * @return 
     */
    @SuppressWarnings("unchecked")
    public List findList(int pageSize, int pageNo, String sql, Class clazz, Object... param) {
        if (pageSize <= 0 || pageNo <= 0) {
            // ?
            return findList(sql, clazz, param);
        }
        SQLQuery query = getSession().createSQLQuery(sql).addEntity(clazz);
        query.setFirstResult(((pageNo - 1) * pageSize));
        query.setMaxResults(pageSize);
        if (param != null && param.length > 0) {
            for (int i = 0; i < param.length; i++) {
                query.setParameter(i, param[i]);
            }
        }
        return query.list();
    }

    /**
     * HQL
     * 
     * @param hql
     *            : hql
     * @param param
     *             ?
     * @return ??
     */
    public int executeHQL(String hql, Object... param) {
        Query query = getSession().createQuery(hql);
        if (param != null && param.length > 0) {
            for (int i = 0; i < param.length; i++) {
                query.setParameter(i, param[i]);
            }
        }
        return query.executeUpdate();
    }

    /**
     * SQL
     * 
     * @param sql
     *            : SQL
     * @param param
     *             ?
     * @return ??
     */
    public int executeSQL(String sql, Object... param) {
        SQLQuery query = getSession().createSQLQuery(sql);
        if (param != null && param.length > 0) {
            for (int i = 0; i < param.length; i++) {
                query.setParameter(i, param[i]);
            }
        }
        return query.executeUpdate();
    }

    /**
     * 
     * 
     * @param id
     * @param clazz
     * @return id
     */
    @SuppressWarnings("unchecked")
    public Object get(PK id, Class clazz, final String... lazyObjects) {
        // StringBuffer hql = new StringBuffer("from ");
        // hql.append(clazz.getName());
        // hql.append(" where id = ?");
        // List l = this.find(hql.toString(), new Object[] { id });
        // if (l == null || l.size() == 0) {
        // return null;
        // } else {
        // return l.get(0);
        // }
        List<PropertyFilter> filters = new ArrayList<PropertyFilter>();
        if (id.getClass().equals(String.class)) {
            filters.add(new PropertyFilter("EQS_id", id));
        } else if (id.getClass().equals(Integer.class)) {
            filters.add(new PropertyFilter("EQI_id", id));
        } else {
            filters.add(new PropertyFilter("EQL_id", id));
        }
        return _get(filters, clazz, lazyObjects);
    }

    public Object get(final List<PropertyFilter> filters, Class clazz, final String... lazyObjects) {
        return _get(filters, clazz, lazyObjects);
    }

    private Object _get(final List<PropertyFilter> filters, Class clazz, final String... lazyObjects) {
        Criteria criteria = getSession().createCriteria(clazz);
        Map<String, Criteria> criteriaMap = new HashMap<String, Criteria>();
        for (PropertyFilter filter : filters) {
            if (!filter.isMultiProperty()) {
                String propertyName = filter.getPropertyName();
                Object[] propertyValue = filter.getPropertyValue();
                MatchType matchType = filter.getMatchType();
                Criteria parent = findParentCriteria(criteria, propertyName, criteriaMap);
                String[] tmp = StringUtils.split(propertyName, DEF_SEPARATOR);
                parent.add(getCriterion(tmp[tmp.length - 1], propertyValue, matchType));
            } else {
                Disjunction disjunction = Restrictions.disjunction();
                Object[] propertyValue = filter.getPropertyValue();
                MatchType matchType = filter.getMatchType();
                for (String propertyName : filter.getPropertyNames()) {
                    Criteria parent = findParentCriteria(criteria, propertyName, criteriaMap);
                    String[] tmp = StringUtils.split(propertyName, DEF_SEPARATOR);
                    parent.add(getCriterion(tmp[tmp.length - 1], propertyValue, matchType));
                }
                criteria.add(disjunction);
            }
        }
        // criteria.setMaxResults(1);

        if (lazyObjects != null) {
            for (int i = 0; i < lazyObjects.length; i++) {
                criteria.setFetchMode(lazyObjects[i], FetchMode.EAGER);
            }
        }

        List result = criteria.list();
        if (result == null || result.size() == 0) {
            return null;
        } else {
            return result.get(0);
        }
    }

    /**
     * ?.
     */
    @SuppressWarnings("unchecked")
    public Page<T> findPage(final Page<T> page, final List<PropertyFilter> filters) {
        return this.findPageDynamicFetch(page, filters);
    }

    @SuppressWarnings("unchecked")
    public Page<T> findPageDynamicFetch(final Page<T> page, final List<PropertyFilter> filters,
            final String... lazyObjects) {
        Criteria criteria = getSession().createCriteria(entityClass);
        Map<String, Criteria> criteriaMap = new HashMap<String, Criteria>();
        for (PropertyFilter filter : filters) {
            if (!MatchType.INS.equals(filter.getMatchType())) {
                if (!filter.isMultiProperty()) {
                    String propertyName = filter.getPropertyName();
                    Object[] propertyValue = filter.getPropertyValue();
                    MatchType matchType = filter.getMatchType();
                    Criteria parent = findParentCriteria(criteria, propertyName, criteriaMap);
                    String[] tmp = StringUtils.split(propertyName, DEF_SEPARATOR);
                    parent.add(getCriterion(tmp[tmp.length - 1], propertyValue, matchType));
                } else {
                    Disjunction disjunction = Restrictions.disjunction();
                    Object[] propertyValue = filter.getPropertyValue();
                    MatchType matchType = filter.getMatchType();
                    String[] propertyNames = filter.getPropertyNames();
                    for (String propertyName : propertyNames) {
                        // Criteria parent = findParentCriteria(criteria,
                        // propertyName, criteriaMap);
                        String[] tmp = StringUtils.split(propertyName, DEF_SEPARATOR);
                        // parent.add(getCriterion(tmp[tmp.length - 1],
                        // propertyValue, matchType));
                        for (int i = 0; i <= tmp.length - 2; i++) {
                            criteria.createAlias(tmp[i], tmp[i], CriteriaSpecification.LEFT_JOIN);
                        }
                        // disjunction.ad
                    }
                    criteria.add(Restrictions.or(
                            Restrictions.like(propertyNames[0], propertyValue[0].toString(), MatchMode.ANYWHERE),
                            Restrictions.like(propertyNames[1], propertyValue[0].toString(), MatchMode.ANYWHERE)));

                    // criteria.add(disjunction);
                }
            } else {
                criteria.add(org.hibernate.criterion.Expression.sql("this_." + filter.getPropertyName() + " in "
                        + String.valueOf(filter.getPropertyValue()[0])));
            }
        }
        if (lazyObjects != null) {
            for (int i = 0; i < lazyObjects.length; i++) {
                criteria.setFetchMode(lazyObjects[i], FetchMode.EAGER);
            }
        }
        if (page != null && page.isAutoCount()) {
            int totalCount = countCriteriaResult(criteria);
            page.setTotalCount(totalCount);
        }
        if (page != null && page.getPageSize() > 0) {
            if (page.getTotalPages() < page.getPageNo()) {
                page.setPageNo(1L);
            }
            criteria.setFirstResult(page.getFirst() - 1);
            criteria.setMaxResults(page.getPageSize());
        }
        if (page != null && page.isOrderBySetted()) {
            String[] orderByArray = StringUtils.split(page.getOrderBy(), ',');
            String[] orderArray = StringUtils.split(page.getOrder(), ',');

            Assert.isTrue(orderByArray.length == orderArray.length, "orderBy and order is not suited!");

            for (int i = 0; i < orderByArray.length; i++) {
                if (orderByArray[i].indexOf(".") > 0) {
                    // ???
                    if (Page.ASC.equals(orderArray[i])) {
                        Criteria p = criteriaMap
                                .get(orderByArray[i].substring(0, orderByArray[i].lastIndexOf(".")));
                        if (p == null) {
                            p = findParentCriteria(criteria, orderByArray[i], criteriaMap);// ??
                        }
                        p.addOrder(Order.asc(orderByArray[i].substring(orderByArray[i].lastIndexOf(".") + 1)));
                    } else {
                        Criteria p = criteriaMap
                                .get(orderByArray[i].substring(0, orderByArray[i].lastIndexOf(".")));
                        if (p == null) {
                            p = findParentCriteria(criteria, orderByArray[i], criteriaMap);// ??
                        }
                        p.addOrder(Order.desc(orderByArray[i].substring(orderByArray[i].lastIndexOf(".") + 1)));
                    }
                } else {
                    if (Page.ASC.equals(orderArray[i])) {
                        criteria.addOrder(Order.asc(orderByArray[i]));
                    } else {
                        criteria.addOrder(Order.desc(orderByArray[i]));
                    }
                }
            }
        }

        List result = criteria.list();
        if (page == null) {
            Page p = new Page<T>();
            p.setResult(result);
            p.setTotalCount(result.size());
            p.setPageNo(1L);
            p.setPageSize(result.size());
            return p;
        }
        page.setResult(result);
        return page;
    }

    /**
     *   OR
     * 
     * @new date 2012-04-23
     * @param page
     * @param filters
     * @return
     */
    @SuppressWarnings("unchecked")
    public Page<T> findPageWithOR(final Page<T> page, final List<PropertyFilter> filters) {
        Criteria criteria = getSession().createCriteria(entityClass);
        Map<String, Criteria> criteriaMap = new HashMap<String, Criteria>();

        for (PropertyFilter filter : filters) {
            if (!filter.isMultiProperty()) {
                String propertyName = filter.getPropertyName();
                createSubCriteria(criteria, propertyName, criteriaMap);
            } else {
                for (String propertyName : filter.getPropertyNames()) {
                    createSubCriteria(criteria, propertyName, criteriaMap);
                }
            }
        }

        boundCriterion(criteria, buildPropertyFilterCriterions(filters));

        if (page != null && page.isAutoCount()) {
            int totalCount = countCriteriaResult(criteria);
            page.setTotalCount(totalCount);
        }
        if (page != null && page.getPageSize() > 0) {
            if (page.getTotalPages() < page.getPageNo()) {
                page.setPageNo(1L);
            }
            criteria.setFirstResult(page.getFirst() - 1);
            criteria.setMaxResults(page.getPageSize());
        }
        if (page != null && page.isOrderBySetted()) {
            String[] orderByArray = StringUtils.split(page.getOrderBy(), ',');
            String[] orderArray = StringUtils.split(page.getOrder(), ',');

            Assert.isTrue(orderByArray.length == orderArray.length, "orderBy and order is not suited!");

            for (int i = 0; i < orderByArray.length; i++) {
                if (orderByArray[i].indexOf(".") > 0) {
                    // ???
                    if (Page.ASC.equals(orderArray[i])) {
                        Criteria p = criteriaMap
                                .get(orderByArray[i].substring(0, orderByArray[i].lastIndexOf(".")));
                        if (p == null) {
                            p = findParentCriteria(criteria, orderByArray[i], criteriaMap);// ??
                        }
                        p.addOrder(Order.asc(orderByArray[i].substring(orderByArray[i].lastIndexOf(".") + 1)));
                    } else {
                        Criteria p = criteriaMap
                                .get(orderByArray[i].substring(0, orderByArray[i].lastIndexOf(".")));
                        if (p == null) {
                            p = findParentCriteria(criteria, orderByArray[i], criteriaMap);// ??
                        }
                        p.addOrder(Order.desc(orderByArray[i].substring(orderByArray[i].lastIndexOf(".") + 1)));
                    }
                } else {
                    if (Page.ASC.equals(orderArray[i])) {
                        criteria.addOrder(Order.asc(orderByArray[i]));
                    } else {
                        criteria.addOrder(Order.desc(orderByArray[i]));
                    }
                }
            }
        }

        List result = criteria.list();
        if (page == null) {
            Page p = new Page<T>();
            p.setResult(result);
            p.setTotalCount(result.size());
            p.setPageNo(1L);
            p.setPageSize(result.size());
            return p;
        }
        page.setResult(result);
        return page;
    }

    /**
     * 
     * 
     * @date 2012-04-06
     * @param page
     * @param filters
     * @param criterions
     * @return
     */
    @SuppressWarnings("unchecked")
    public Page<T> findPage(final Page<T> page, final List<PropertyFilter> filters, final Criterion... criterions) {
        Assert.notNull(page, "page should not be null!");

        Criterion[] cs = (Criterion[]) ArrayUtils.addAll(buildPropertyFilterCriterions(filters), criterions);
        Criteria c = createCriteria(cs);

        if (page.isAutoCount()) {
            int totalCount = countCriteriaResult(c);
            page.setTotalCount(totalCount);
        }
        if (page != null && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameter(c, page);
        List<T> result = c.list();
        page.setResult(result);

        return page;
    }

    /**
     * 
     * 
     * @date 2012-04-06
     * @param page
     * @param filters
     * @param criterions
     * @return
     */
    @SuppressWarnings("unchecked")
    public Page<T> findPage(final Page<T> page, final List<PropertyFilter> filters, String[] fetchObject,
            final Criterion... criterions) {
        Assert.notNull(page, "page should not be null!");

        Criterion[] cs = (Criterion[]) ArrayUtils.addAll(buildPropertyFilterCriterions(filters), criterions);
        Criteria c = createCriteria(cs);

        if (page.isAutoCount()) {
            int totalCount = countCriteriaResult(c);
            page.setTotalCount(totalCount);
        }
        if (page != null && page.getPageSize() > 0 && page.getTotalPages() < page.getPageNo()) {
            page.setPageNo(1L);
        }

        setPageParameter(c, page);
        if (fetchObject != null) {
            for (int i = 0; i < fetchObject.length; i++) {
                c.setFetchMode(fetchObject[i], FetchMode.JOIN);
            }
        }
        List<T> result = c.list();
        page.setResult(result);

        return page;
    }

    /**
     * ?Criteriabulletin.channel.valid,bulletin.channel
     * 
     * @return
     */
    private Criteria findParentCriteria(Criteria root, String propertyName, Map<String, Criteria> criteriaMap) {
        if (propertyName.indexOf(DEF_SEPARATOR) > 0) {
            String parentName = propertyName.substring(0, propertyName.lastIndexOf(DEF_SEPARATOR));
            Criteria t = criteriaMap.get(parentName);
            if (t == null) {
                Criteria p = findParentCriteria(root, parentName, criteriaMap);
                String[] tmp = StringUtils.split(parentName, DEF_SEPARATOR);
                Criteria c = p.createCriteria(tmp[tmp.length - 1], CriteriaSpecification.LEFT_JOIN);
                criteriaMap.put(parentName, c);
                return c;
            } else {
                return t;
            }
        } else {
            return root;
        }
    }

    /**
     * [findPageWithOR]  ?
     * 
     * @new date 2012-04-23
     * @param criteria
     * @param propertyName
     * @param criteriaMap
     */
    private void createSubCriteria(Criteria criteria, String propertyName, Map<String, Criteria> criteriaMap) {
        if (propertyName.indexOf(DEF_SEPARATOR) > 0) {
            String parentName = propertyName.substring(0, propertyName.indexOf(DEF_SEPARATOR));
            propertyName = propertyName.substring(propertyName.indexOf(DEF_SEPARATOR) + 1);
            Criteria sub = null;
            if (!criteriaMap.containsKey(parentName)) {
                sub = criteria.createAlias(parentName, parentName, CriteriaSpecification.LEFT_JOIN);
                criteriaMap.put(parentName, sub);
            } else {
                sub = criteriaMap.get(parentName);
            }
            createSubCriteria(sub, propertyName, criteriaMap);
        }
    }

    /**
     * [findPageWithOR]  ??
     * 
     * @new date 2012-04-23
     * @param criteria
     * @param criterions
     * @return
     */
    public Criteria boundCriterion(Criteria criteria, final Criterion... criterions) {
        for (Criterion c : criterions) {
            criteria.add(c);
        }
        return criteria;
    }

    /**
     * ?Criterion,.
     */
    protected Criterion[] buildPropertyFilterCriterions(final List<PropertyFilter> filters) {
        List<Criterion> criterionList = new ArrayList<Criterion>();
        for (PropertyFilter filter : filters) {
            if (!filter.isMultiProperty()) { // ??.
                Criterion criterion = buildPropertyFilterCriterion(filter.getPropertyName(),
                        filter.getPropertyValue(), filter.getMatchType());
                criterionList.add(criterion);
            } else {// ??,or?.
                Disjunction disjunction = Restrictions.disjunction();
                for (String param : filter.getPropertyNames()) {
                    Criterion criterion = buildPropertyFilterCriterion(param, filter.getPropertyValue(),
                            filter.getMatchType());
                    disjunction.add(criterion);
                }
                criterionList.add(disjunction);
            }
        }
        return criterionList.toArray(new Criterion[criterionList.size()]);
    }

    /**
     * ??Criterion,.
     */
    protected Criterion buildPropertyFilterCriterion(final String propertyName, final Object[] propertyValue,
            final MatchType matchType) {
        Assert.hasText(propertyName, "propertyName should not be null!");
        Criterion criterion = null;
        try {
            // ?MatchTypecriterion
            if (MatchType.EQ.equals(matchType)) {
                criterion = Restrictions.eq(propertyName, propertyValue[0]);
            } else if (MatchType.LIKE.equals(matchType)) {
                criterion = Restrictions.like(propertyName, (String) propertyValue[0], MatchMode.ANYWHERE);
            } else if (MatchType.ELIKE.equals(matchType)) {
                criterion = Restrictions.like(propertyName, (String) propertyValue[0], MatchMode.END);
            } else if (MatchType.SLIKE.equals(matchType)) {
                criterion = Restrictions.like(propertyName, (String) propertyValue[0], MatchMode.START);
            } else if (MatchType.LE.equals(matchType)) {
                criterion = Restrictions.le(propertyName, propertyValue[0]);
            } else if (MatchType.LT.equals(matchType)) {
                criterion = Restrictions.lt(propertyName, propertyValue[0]);
            } else if (MatchType.GE.equals(matchType)) {
                criterion = Restrictions.ge(propertyName, propertyValue[0]);
            } else if (MatchType.GT.equals(matchType)) {
                criterion = Restrictions.gt(propertyName, propertyValue[0]);
            } else if (MatchType.NE.equals(matchType)) {
                criterion = Restrictions.ne(propertyName, propertyValue[0]);
            } else if (MatchType.ISNULL.equals(matchType)) {
                criterion = Restrictions.isNull(propertyName);
            } else if (MatchType.ISNOTNULL.equals(matchType)) {
                criterion = Restrictions.isNotNull(propertyName);
            } else if (MatchType.ISEMPTY.equals(matchType)) {
                criterion = Restrictions.isEmpty(propertyName);
            } else if (MatchType.ISNOTEMPTY.equals(matchType)) {
                criterion = Restrictions.isNotEmpty(propertyName);
            } else if (MatchType.IN.equals(matchType)) {
                criterion = Restrictions.in(propertyName, propertyValue);
            }
        } catch (Exception e) {
            throw ReflectionUtils.convertReflectionExceptionToUnchecked(e);
        }
        return criterion;
    }

    /**
     * ??.
     * 
     * ,(value)?(orgValue)?.
     */
    public boolean isPropertyUnique(final String propertyName, final Object newValue, final Object oldValue) {
        if (newValue == null || newValue.equals(oldValue)) {
            return true;
        }
        Object object = findUniqueBy(propertyName, newValue);
        return (object == null);
    }

    /**
     * ??
     */
    private Criterion getCriterion(String propertyName, Object[] propertyValue, MatchType matchType) {
        Criterion criterion = null;
        try {
            // ?MatchTypecriterion
            if (MatchType.EQ.equals(matchType)) {
                criterion = Restrictions.eq(propertyName, propertyValue[0]);
            } else if (MatchType.LIKE.equals(matchType)) {
                criterion = RestrictionsUtils.ilike(propertyName, String.valueOf(propertyValue[0]),
                        MatchMode.ANYWHERE);
            } else if (MatchType.ELIKE.equals(matchType)) {
                criterion = RestrictionsUtils.ilike(propertyName, (String) propertyValue[0], MatchMode.END);
            } else if (MatchType.SLIKE.equals(matchType)) {
                criterion = RestrictionsUtils.ilike(propertyName, (String) propertyValue[0], MatchMode.START);
            } else if (MatchType.LE.equals(matchType)) {
                criterion = Restrictions.le(propertyName, propertyValue[0]);
            } else if (MatchType.LT.equals(matchType)) {
                criterion = Restrictions.lt(propertyName, propertyValue[0]);
            } else if (MatchType.GE.equals(matchType)) {
                criterion = Restrictions.ge(propertyName, propertyValue[0]);
            } else if (MatchType.GT.equals(matchType)) {
                criterion = Restrictions.gt(propertyName, propertyValue[0]);
            } else if (MatchType.NE.equals(matchType)) {
                criterion = Restrictions.ne(propertyName, propertyValue[0]);
            } else if (MatchType.ISNULL.equals(matchType)) {
                criterion = Restrictions.isNull(propertyName);
            } else if (MatchType.ISNOTNULL.equals(matchType)) {
                criterion = Restrictions.isNotNull(propertyName);
            } else if (MatchType.ISEMPTY.equals(matchType)) {
                criterion = Restrictions.isEmpty(propertyName);
            } else if (MatchType.ISNOTEMPTY.equals(matchType)) {
                criterion = Restrictions.isNotEmpty(propertyName);
            } else if (MatchType.IN.equals(matchType)) {
                criterion = Restrictions.in(propertyName, propertyValue);
            } else if (MatchType.LEN.equals(matchType)) {
                criterion = Restrictions.le(propertyName, propertyValue[0]);
            }
        } catch (Exception e) {
            throw ReflectionUtils.convertReflectionExceptionToUnchecked(e);
        }
        return criterion;
    }

    /**
     * hibernate?
     * 
     */
    public void evictEntity(final T entity) {
        if (entity != null) {
            getSession().evict(entity);
        }
    }

    /**
     * ?sql
     */
    @SuppressWarnings("unchecked")
    public T findSQLNonHibernateEntity(final String sql, final Map<String, Object> values) {
        Query query = createSQLQuery(sql, values).setResultTransformer(Transformers.aliasToBean(entityClass));
        query.setMaxResults(1);
        return (T) query.uniqueResult();
    }

    public List<T> findDynamicFetch(final List<PropertyFilter> filters, String orderBy, String order,
            final String... lazyObjects) {
        Criteria criteria = getSession().createCriteria(entityClass);
        Map<String, Criteria> criteriaMap = new HashMap<String, Criteria>();
        for (PropertyFilter filter : filters) {
            if (!filter.isMultiProperty()) {
                String propertyName = filter.getPropertyName();
                Object[] propertyValue = filter.getPropertyValue();
                MatchType matchType = filter.getMatchType();
                Criteria parent = findParentCriteria(criteria, propertyName, criteriaMap);
                String[] tmp = StringUtils.split(propertyName, DEF_SEPARATOR);
                parent.add(getCriterion(tmp[tmp.length - 1], propertyValue, matchType));
            } else {
                Disjunction disjunction = Restrictions.disjunction();
                Object[] propertyValue = filter.getPropertyValue();
                MatchType matchType = filter.getMatchType();
                for (String propertyName : filter.getPropertyNames()) {
                    Criteria parent = findParentCriteria(criteria, propertyName, criteriaMap);
                    String[] tmp = StringUtils.split(propertyName, DEF_SEPARATOR);
                    parent.add(getCriterion(tmp[tmp.length - 1], propertyValue, matchType));

                }
                criteria.add(disjunction);
            }
        }

        if (orderBy != null && !"".equals(orderBy)) {
            String[] orderByArray = StringUtils.split(orderBy, ',');
            String[] orderArray = StringUtils.split(order, ',');

            Assert.isTrue(orderByArray.length == orderArray.length, "orderBy and order is not suited!");

            for (int i = 0; i < orderByArray.length; i++) {
                if (orderByArray[i].indexOf(".") > 0) {
                    // ???
                    if (Page.ASC.equals(orderArray[i])) {
                        Criteria p = criteriaMap
                                .get(orderByArray[i].substring(0, orderByArray[i].lastIndexOf(".")));
                        if (p == null) {
                            p = findParentCriteria(criteria, orderByArray[i], criteriaMap);// ??
                        }
                        p.addOrder(Order.asc(orderByArray[i].substring(orderByArray[i].lastIndexOf(".") + 1)));
                    } else {
                        Criteria p = criteriaMap
                                .get(orderByArray[i].substring(0, orderByArray[i].lastIndexOf(".")));
                        if (p == null) {
                            p = findParentCriteria(criteria, orderByArray[i], criteriaMap);// ??
                        }
                        p.addOrder(Order.desc(orderByArray[i].substring(orderByArray[i].lastIndexOf(".") + 1)));
                    }
                } else {
                    if (Page.ASC.equals(orderArray[i])) {
                        criteria.addOrder(Order.asc(orderByArray[i]));
                    } else {
                        criteria.addOrder(Order.desc(orderByArray[i]));
                    }
                }
            }
        }

        if (lazyObjects != null) {
            for (int i = 0; i < lazyObjects.length; i++) {
                criteria.setFetchMode(lazyObjects[i], FetchMode.JOIN);
            }
        }
        criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
        List result = criteria.list();

        return result;
    }
}