天天看点

Hibernate之DetachedCriteria类详解

首先看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对象

Hibernate之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的强大!!

继续阅读