package com.jrails.modules.orm.dao;
import org.springside.modules.utils.BeanUtils;
import org.hibernate.SessionFactory;
import org.hibernate.Query;
import org.hibernate.Criteria;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.impl.CriteriaImpl;
import org.hibernate.criterion.*;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.ArrayList;
import com.jrails.page.TablePage;
import com.jrails.page.Page;
import com.jrails.commons.utils.SqlStringUtils;
/**
* Created by arden
* User: <a href="mailto:arden.emily@gmail.com">arden</a>
* Date: 2009-2-13 12:47:29
*/
public class JrailsDao<T, PK extends java.io.Serializable> extends HibernateTemplate {
// 获得记录业务相关的日志记录器
protected static final Logger logger = LoggerFactory.getLogger(JrailsDao.class);
protected Class<T> entityClass;
@Autowired
public JrailsDao(@Qualifier("sessionFactory")SessionFactory sessionFactory, Class<T> entityClass) {
super(sessionFactory);
this.entityClass = entityClass;
}
public void delete(PK id) {
Assert.notNull(id);
this.delete(this.get(this.entityClass, id));
}
public List<T> findAll(boolean cacheable) {
return findByCriteria(cacheable);
}
public TablePage<T> findAll(TablePage<T> page, boolean cacheable) {
return findByCriteria(page, cacheable);
}
/**
* 按id获取对象.
*/
public T get(final PK id) {
return (T) getSession().load(entityClass, id);
}
/**
* 按HQL查询对象列表.
*
* @param hql hql语句
* @param values 数量可变的参数
*/
public List find(String hql, boolean cacheable, Object... values) {
return createQuery(hql, cacheable, values).list();
}
/**
* 按HQL分页查询.
* 暂不支持自动获取总结果数,需用户另行执行查询.
*
* @param page 分页参数.包括pageSize 和firstResult.
* @param hql hql语句.
* @param values 数量可变的参数.
*
* @return 分页查询结果,附带结果列表及所有查询时的参数.
*/
public TablePage<T> find(TablePage<T> page, String hql, boolean cacheable, Object... values) {
Assert.notNull(page);
if (page.isAutoCount()) {
String countHql = SqlStringUtils.getCountString(hql);
int totalCount = this.findLong(countHql, cacheable, values).intValue();
page.setTotalCount(totalCount);
//logger.warn("HQL查询暂不支持自动获取总结果数,hql为{}", hql);
}
Query q = createQuery(hql, cacheable, values);
if (page.isFirstSetted()) {
q.setFirstResult(page.getFirst());
}
if (page.isPageSizeSetted()) {
q.setMaxResults(page.getPageSize());
}
page.setResult(q.list());
return page;
}
/**
* 按HQL查询唯一对象.
*/
public Object findUnique(String hql, boolean cacheable, Object... values) {
return createQuery(hql, cacheable, values).uniqueResult();
}
/**
* 按HQL查询Intger类形结果.
*/
public Integer findInt(String hql, boolean cacheable, Object... values) {
return (Integer) findUnique(hql, cacheable, values);
}
/**
* 按HQL查询Long类型结果.
*/
public Long findLong(String hql, boolean cacheable, Object... values) {
return (Long) findUnique(hql, cacheable, values);
}
/**
* 按Criterion查询对象列表.
* @param criterion 数量可变的Criterion.
*/
public List<T> findByCriteria(boolean cacheable, Criterion... criterion) {
return createCriteria(cacheable, criterion).list();
}
/**
* 按Criterion分页查询.
* @param page 分页参数.包括pageSize、firstResult、orderBy、asc、autoCount.
* 其中firstResult可直接指定,也可以指定pageNo.
* autoCount指定是否动态获取总结果数.
*
* @param criterion 数量可变的Criterion.
* @return 分页查询结果.附带结果列表及所有查询时的参数.
*/
public TablePage<T> findByCriteria(TablePage page, boolean cacheable, Criterion... criterion) {
Assert.notNull(page);
Criteria c = createCriteria(cacheable, criterion);
if (page.isAutoCount()) {
page.setTotalCount(countQueryResult(page, c));
}
if (page.isFirstSetted()) {
c.setFirstResult(page.getFirst());
}
if (page.isPageSizeSetted()) {
c.setMaxResults(page.getPageSize());
}
if (page.isOrderBySetted()) {
if (page.getOrder().endsWith(TablePage.ASC)) {
c.addOrder(Order.asc(page.getOrderBy()));
} else {
c.addOrder(Order.desc(page.getOrderBy()));
}
}
page.setResult(c.list());
return page;
}
/**
* 按属性查找对象列表.
*/
public List<T> findByProperty(String propertyName, boolean cacheable, Object value) {
Assert.hasText(propertyName);
return createCriteria(cacheable, Restrictions.eq(propertyName, value)).list();
}
/**
* 按属性查找唯一对象.
*/
public T findUniqueByProperty(String propertyName, boolean cacheable, Object value) {
Assert.hasText(propertyName);
return (T) createCriteria(cacheable, Restrictions.eq(propertyName, value)).uniqueResult();
}
/**
* 根据查询函数与参数列表创建Query对象,后续可进行更多处理,辅助函数.
*/
public Query createQuery(String queryString, boolean cacheable, Object... values) {
Assert.hasText(queryString);
Query queryObject = getSession().createQuery(queryString);
if (cacheable) {
queryObject.setCacheable(cacheable);
}
if (values != null) {
for (int i = 0; i < values.length; i++) {
queryObject.setParameter(i, values[i]);
}
}
return queryObject;
}
/**
* 根据Criterion条件创建Criteria,后续可进行更多处理,辅助函数.
*/
public Criteria createCriteria(boolean cacheable, Criterion... criterions) {
Criteria criteria = getSession().createCriteria(entityClass);
if (cacheable) {
criteria.setCacheable(cacheable);
}
for (Criterion c : criterions) {
criteria.add(c);
}
return criteria;
}
/**
* 判断对象的属性值在数据库内是否唯一.
*
* 在修改对象的情景下,如果属性新修改的值(value)等于属性原值(orgValue)则不作比较.
* 传回orgValue的设计侧重于从页面上发出Ajax判断请求的场景.
* 否则需要SS2里那种以对象ID作为第3个参数的isUnique函数.
*/
public boolean isPropertyUnique(String propertyName, boolean cacheable, Object newValue, Object orgValue) {
if (newValue == null || newValue.equals(orgValue))
return true;
Object object = findUniqueByProperty(propertyName, cacheable, newValue);
return (object == null);
}
/**
* 通过count查询获得本次查询所能获得的对象总数.
* @return page对象中的totalCount属性将赋值.
*/
protected int countQueryResult(Page<T> page, 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) BeanUtils.getFieldValue(impl, "orderEntries");
BeanUtils.setFieldValue(impl, "orderEntries", new ArrayList());
} catch (Exception e) {
logger.error("不可能抛出的异常:{}", e.getMessage());
}
// 执行Count查询
int totalCount = (Integer) c.setProjection(Projections.rowCount()).uniqueResult();
if (totalCount < 1)
return -1;
// 将之前的Projection和OrderBy条件重新设回去
c.setProjection(projection);
if (projection == null) {
c.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
}
if (transformer != null) {
c.setResultTransformer(transformer);
}
try {
BeanUtils.setFieldValue(impl, "orderEntries", orderEntries);
} catch (Exception e) {
logger.error("不可能抛出的异常:{}", e.getMessage());
}
return totalCount;
}
}