参考:http://javaeyetianjin.group.iteye.com/group/topic/10621

QBE:query by Example
QBC:query by Criteria
Criteria:代表一次查询
Creterion:代表一个查询条件
Restrictions:产生查询条件的工具类
Example继承Criterion
DetachedCriteria继承CriteriaSpecification
Criteria也继承CriteriaSpecification





1.DetachedCriteria



在常规的Web编程中,有大量的动态条件查询,即用户在网页上面自由选择某些条件,程序根据用户的选择条件,动态生成SQL语句,进行查询。



DetachedCriteria可以解决这个问题,即在web层,程序员使用DetachedCriteria来构造查询条件,然后将这个DetachedCriteria作为方法调用参数传递给业务层对象。而业务层对象获得DetachedCriteria之后,可以在session范围内直接构造Criteria,进行查询。就此,查询语句的构造完全被搬离到web层实现,而业务层则只负责完成持久化和查询的封装即可,与查询条件构造完全解耦,非常完美!这恐怕也是以前很多企图在web层代码中构造HQL语句的人想实现的梦想吧!



示例代码片段如下:



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内执行之。这样代码就可放之四海而皆准,都无须修改了




比较一个属性可以这样:


detachedCriteria.add(Restrictions.eq(XXX.PROP_ID,Integer.parseInt(id)));




如果比较的属性本身类型是对象,那么可以这样



detachedCriteria.add(Restrictions.eq(XXX.PROP_BM+".id",Integer.parseInt(bmid)));




以上面的语句为例,如果我比较其他属性


detachedCriteria.add(Restrictions.eq(XXX.PROP_BM+".bmmc",bmmc));




这样是不行的



解决方法:先定义一个别名


detachedCriteria.createAlias(XXX.PROP_BM, "bm");

然后可以这样使用了


detachedCriteria.add("bm.bmmc",bmmc));





个人总结:不使用别名,本身是对象的属性后面只能跟其主键属性,比较其他属性要用别名




2.Criteria


Criteria对SQL进行封装,让开发人员可以用对象的方式来对数据库进行操作,例如下面的查询User表格中的


所有数据:



Criteria criteria = session.createCriteria(User.class);
// 查询user所有字段
List users = criteria.list();
Iterator iterator =  users.iterator();
System.out.println("id \t name/age");
while(iterator.hasNext()) {
    User user = (User) iterator.next(); 
    System.out.println(user.getId() +
                               " \t " + user.getName() +
                               "/" + user.getAge());            
}





Hibernate实际上使用以下的SQL来查询数据库:



select this_.id as id0_, this_.name as name0_0_, this_.age as age0_0_ from user this_





Criteria实际上只是个容器,如果想要设定查询条件,则要使用add()方法加入Restrictions的条件限制,例


如查询age大于20且小于40的数据:



Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.gt("age", new Integer(20)));
criteria.add(Restrictions.lt("age", new Integer(40)));
List users = criteria.list();





您也可以使用逻辑组合来进行查询,例如结合age等于(eq)20或(or)age为空(isNull)的条件:



Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.or( 
                   Restrictions.eq("age", new Integer(20)), 
                   Restrictions.isNull("age") 
               )); 
List users = criteria.list();





也可以使用sqlRestriction()方法来提供SQL语法作限定查询,例如查询name以cater开头的数据:



Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.sqlRestriction("{alias}.name LIKE (?)", "cater%", Hibernate.STRING));
List users = criteria.list();





其中alias将被替换为与User类别相关的名称,而?将被替换为cater%,也就是第二个参数所提供的值,在SQL


撰写时,不必再写WHERE,如果有多个查询条件,例如BETWEEN子句的查询,则可以如下:



Criteria criteria = session.createCriteria(User.class);
Integer[] ages = {new Integer(20), new Integer(40)};
Type[] types = {Hibernate.INTEGER, Hibernate.INTEGER};
criteria.add(Restrictions.sqlRestriction("{alias}.age BETWEEN (?) AND (?)", ages, types));
List users = criteria.list();




3.Restrictions




Restrictions的几个常用限定查询方法如下表所示:


方法 说明 
Restrictions.eq 等于 
Restrictions.allEq 使用Map,使用key/value进行多个等于的比对 
Restrictions.gt 大于 > 
Restrictions.ge 大于等于 >= 
Restrictions.lt 小于 < 
Restrictions.le 小于等于 <= 
Restrictions.between 对应SQL的BETWEEN子句 
Restrictions.like 对应SQL的LIKE子句 
Restrictions.in 对应SQL的in子句 
Restrictions.and and关系 
Restrictions.or or关系 
Restrictions.sqlRestriction SQL限定查询





4.Example


示例查询是通过Example类来完成的,Example类实现了Criterion接口,可以用作Criteria查询条件,Example类的作用是:根据已有对象,查询属性值与之相同的其他对象。如下代码所示:


Criteria criteria=session.createCriteria(User.class); 
            User exampleuser=new User(“zx”); 
            criteria.add(Example.create(exampleuser)); 
            List list=criteria.list(); 
            for(int i=0;i 
               User user=(User)list.get(i); 
               System.out.println(user.getName()+”\n”); 
            }



上述代码中


User exampleuser=new 
            User(“zx”);criteria.add(Example.create(exampleuser));
	    两句相当于 
            criteria.add(Expression.eq(“name”,”zx”));
	    因此会生成类似如下的SQL语句: 
            select * from user where name=’zx’;在上面的代码中exampleuser称为示例对象。




在Hibernate中队示例查询,默认情况下会排除掉示例对象中属性值为空的属性,还可以调用Example.excludeNone(排除空串值)/excludeZeros(排除零值),或者调用Example.excludeProperty方法来指定排除特定属性。



示例查询主要应用于组合查询中,比如根据用户输入的查询条件动态生成最终的查询语句,通过使用示例查询,可以避免由于查询条件过多而写的大量if判断语句。




5.区别


Criteria 和 DetachedCriteria 的主要区别在于创建的形式不一样, Criteria 是在线的,所以它是由 Hibernate Session 进行创建的;而 DetachedCriteria 是离线的,创建时无需 Session , DetachedCriteria 提供了 4 个静态方法 forClass(Class) 或 forEntityName(Name) 进行 DetachedCriteria 实例的创建。 Spring 的框架提供了getHibernateTemplate().findByCriteria(detachedCriteria) 方法可以很方便地根据 DetachedCriteria 来返回查询结果




6.QBC


在Hibernate应用中使用QBC查询通常经过3个步骤


(1)使用Session实例的createCriteria()方法创建Criteria对象


(2)使用工具类Restrictions的相关方法为Criteria对象设置查询对象


(3)使用Criteria对象的list()方法执行查询,返回查询结果




QBC分页查询


Criteria为我们提供了两个有用的方法:setFirstResult(int firstResult)和setMaxResults(int maxResults).


setFirstResult(int firstResult)方法用于指定从哪一个对象开始检索(序号从0开始),默认为第一个对象(序号为0);setMaxResults(int maxResults)方法用于指定一次最多检索出的对象数目,默认为所有对象。




Java代码


Session session = HibernateSessionFactory.getSessionFactory().openSession();    
Transaction ts = null;    
Criteria criteria = session.createCriteria(Order.class);    
int pageSize = 15;    
int pageNo = 1;    
criteria.setFirstResult((pageNo-1)*pageSize);    
criteria.setMaxResults(pageSize);    
Iterator it = criteria.list().iterator();    
ts.commit();    
HibernateSessionFactory.closeSession();