Hibernate3支持DetachedCriteria 在spring上的应用

示例代码片段如下:

  web层程序构造查询条件:

  java代码:
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岁;

  业务层对象使用该条件执行查询:

  java代码:
detachedCriteria.getExecutableCriteria(session).list();

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

  然而Spring和Hibernate3的DetachedCriteria有不兼容的问题,因此在Spring环境下面使用Hibernate3需要注意: ()

  Spring的HibernateTemplate提供了Hibernate的完美封装,即通过匿名类实现回调,来保证Session的自动资源管理和事务的管理。其中核心方法是:

  java代码:
HibernateTemplate.execute(new HibernateCallback() {
 public Object doInHibernate(Session session) throws HibernateException {
  ....
 }
}
  回调方法提供了session作为参数,有了session,就可以自由的使用Hibernate API编程了。使用了spring的之后,代码修改如下:

  web层代码:

  java代码:
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如下:

  java代码:
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(); 
  } 
 }); 
} 

  实际上也就是:

  java代码:
Criteria criteria = detachedCriteria.getExecutableCriteria(session); 
return criteria.list(); 

  而已

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

  我跟踪了一下spring和Hibernate源代码,原因如下:

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

  java代码:
private boolean exposeNativeSession = false;


execute方法内部:
Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy(session)); 



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

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




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

  java代码:

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(); 
  } 
 }, true); 
} 

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