hibernate3中的离线查询2

DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Department.class);
detachedCriteria.add(Restrictions.eq("name", "department")).createAlias("employees", "e").add(Restrictions.gt(("e.age"), new Integer(20)));

Department和Employee是一对多关联,查询条件为:
名称是“department”开发部门;
部门里面的雇员年龄大于20岁;

业务层对象使用该条件执行查询:
detachedCriteria.getExecutableCriteria(session).list();

最大的意义在于,业务层代码是固定不变的,所有查询条件的构造都在web层完成,业务层只负责在session内执行之。这样代码就可放之四海而皆准,都无须修改了。

然而Spring和Hibernate3的DetachedCriteria有不兼容的问题,因此在Spring环境下面使用Hibernate3需要注意:
Spring的HibernateTemplate提供了Hibernate的完美封装,即通过匿名类实现回调,来保证Session的自动资源管理和事务的管理。其中核心方法是:

HibernateTemplate.execute(new HibernateCallback() {
 public Object doInHibernate(Session session) throws HibernateException {
  ....
 }
}

回调方法提供了session作为参数,有了session,就可以自由的使用Hibernate API编程了。使用了spring的之后,代码修改如下:
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Department.class);
detachedCriteria.createAlias("employees", "e").add(Restrictions.eq("name", "department")).add(Restrictions.gt(("e.age"), new Integer(20)));
departmentManager.findByCriteria(detachedCriteria);

构造detachedCriteria,作为参数传递给departmentManager

业务层代码使用spring,DepartmentManager的findByCriteria如下:
public List findByCriteria(final DetachedCriteria detachedCriteria) {
 return (List) getHibernateTemplate().execute(new HibernateCallback() {
  public Object doInHibernate(Session session) throws HibernateException {
   Criteria criteria = detachedCriteria.getExecutableCriteria(session);
   return criteria.list();
  }
 });
}


但是该程序代码执行,会抛出强制类型转换异常!原因如下:

spring的HibernateTemplate的execute方法提供的回调接口具有Session作为参数,但是实际上,默认情况下,HibernateTemplate传递给回调接口的session并不是org.hibernate.impl.SessionImpl类,而是SessionImpl类的一个Proxy类。之所以替换成为一个Proxy类,HibernateTemplate的注释说明,Proxy提供了一些额外的功能,包括自动设置Cachable,Transaction的超时时间,Session资源的更积极的关闭等等。

private boolean exposeNativeSession = false;
... 

execute方法内部:

Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy(session));

  但是遗憾的是,Hibernate的DetachedCriteria的setExecutableCriteria方法却要求将session参数强制转为SessionImpl,但是spring传过来的却是一个Proxy类,因此就报错了。

public Criteria getExecutableCriteria(Session session) {
 impl.setSession( (SessionImpl) session ); // 要求SessionImpl,Spring传递的是Proxy
 return impl;
}

解决方法,禁止Spring的HibernateTemplate传递Proxy类,强制要求它传递真实的SessionImpl类,即给exexute方法增加一个参数,提供参数为true,如下:

public List findByCriteria(DetachedCriteria criteria){
ConstantDAO ctdao = new ConstantDAO();
Session session = getSession();
Transaction tran = session.beginTransaction();
Criteria cri = criteria.getExecutableCriteria(session);
List list = cri.list();
tran.commit();
session.close();
return list;
}

你可能感兴趣的:(spring,编程,Hibernate,Web)