首先看DetachedCriteria这个类名,是由两个单词(detached和criteria)组成的,Criteria咱们知道是QBC查询主要接口之一,它通过组装各种Criterion对象来获取实体,Hibernate中的Session是产生Criteria的工厂,Criterion实例一般来说都是通过Restrictions类获取的,如下面这个例子:
List cats = session.createCriteria(Cat.class)
.add( Restrictions.like("name", "Iz%") )
.add( Restrictions.gt( "weight", new Float(minWeight) ) )
.addOrder( Order.asc("age") )
.list();
通过上述例子可以发现需要使用Session实例来获取Criteria对象,再看另外一个单词detached,意思为“分离的、分开的、分割的、未绑定依附的”意思,那到底跟谁分离、分开呢?对,就是session,也就是说两个单词合起来的意思是该类除了创建时不在依附于任何Session,但可以完整支持Criteria的功能,这就是DetachedCriteria的诞生的根本需求;
下面咱们再来讨论下该类的应用场景:
在常规的Web编程中,有大量的动态条件查询,即用户在网页上面根据自身需要选择录入某些条件,程序根据用户选择内容,动态生成查询SQL语句,进行查询。
针对这种需求,对于分层应用程序来说,Web层需要传递一个包含了查询的条件条件的列表给业务层对象(传统上使用Map对象),业务层对象获得这个条件列表之后,依次从列表取出条件,构造查询语句。这里的一个难点是条件列表用什么来构造?那么这么做的缺陷就是Map对象可以传递的信息非常有限,只能传递name和value,无法传递究竟要做怎样的条件运算,即这么name和value之间什么关系,是>,<,IN,AND,OR呢?这就要求业务层对象必须确切掌握每条entry的隐含条件。因此一旦隐含条件改变,业务层对象的查询构造算法必须相应修改,但是这种查询条件的改变是隐式约定的,而不是程序代码约束的,因此非常容易出错。DetachedCriteria的出现解决了上述问题;
下面介绍一下DetachedCriteria的日常使用;
1、DetachedCriteria类允许你在Hibernate的Session范围外创建一个查询,然后使用任意一个Session环境去执行它,这种用法也是使用最多的用法,该类提供了如下两个方法用以构建DetachedCriteria对象
代码如下:
// 创建DetachedCriteria对象
DetachedCriteria query = DetachedCriteria.forClass(Cat.class).add( Property.forName("sex").eq('F') );
// 获取Session对象
Session session = ....;
// 开启事务
Transaction txn = session.beginTransaction();
// 将DetachedCriteria查询对象与可执行的Criteria实例关联起来
List results = query.getExecutableCriteria(session).setMaxResults(100).list();
// 提交事务
txn.commit();
// 关闭Session,释放资源
session.close();
2、一个DetachedCriteria可用作子查询,Criterion实例可以通过Subqueries和Property类调用DetachedCriteria构建的子查询,如下代码所示:
// 构建所有Cat中的平均体重
DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
.setProjection(Property.forName("weight").avg());
// 获取所有Cat中,高于平均提供的Cat的集合
session.createCriteria(Cat.class).add(Property.forName("weight").gt(avgWeight))
.list();
// 构建所有Cat的提供集合列表
DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
.setProjection(Property.forName("weight"));
// 获取所有Cat中,体重最大的Cat
session.createCriteria(Cat.class).add(Subqueries.geAll("weight", weights))
.list();
}
关联子查询,即DetachedCriteria构建的子查询和Criteria构建的查询也可以直接交互,如下:
DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
.setProjection(Property.forName("weight").avg()).add(Property.forName("cat2.sex").eqProperty(
"cat.sex"));
session.createCriteria(Cat.class,"cat").add(Property.forName("weight").gt(avgWeightForSex)).list();
最后在上一个当用DetachedCriteria构建的投影,有多个列的例子:
DetachedCriteria sizeQuery = DetachedCriteria
.forClass(SlEmployee.class).setProjection(Projections.projectionList()
.add(Projections.property("userName"))
.add(Projections.property("employeeName")))
.add(Restrictions.eq("userName", "CHENGYU"));
List list = session.createCriteria(SlEmployee.class)
.add(Subqueries.propertiesEq(new String[] { "userName", "employeeName" }, sizeQuery)).list();
实际项目中用的最多的是第一种用法,即用来构建一个查询对象,对于子查询这种用法则用的较少,通过例子可以看出,子查询的功能似乎才更能体现出DetachedCriteria的强大!!