Hibernate中的QBC(criteria 和 DetachedCriteria)

来源:互联网 发布:外国人评价三体 知乎 编辑:程序博客网 时间:2024/05/17 18:46

一.条件查询

条件查询是根据面向对象特色的数据查询方式,条件查询通过如下三个类完成:

1>Criteria:代表一次查询

2>Criterion:代表一个查询条件

3>Restrictions:产生查询条件的工具类

执行条件查询的步骤如下:

1>获得hibernate的Session对象

2>以Session对象创建Criteria对象

3>使用Restrictions的静态方法创建Criterion查询条件

4>向Criteria查询中添加Criterion查询条件

5>执行Criteria的list()或uniqueResult()方法返回结果集


现在假设有一个Student类,内有id,name,age属性
String hql = "from Student s";
按照以前的做法,我们通常是
Query query = session.createQuery(hql);
或者要按照条件检索的话.
String hql = "from Student s where s.name like '王%'"
Query query = session.createQuery(hql);
不用HQL而使用QBC的话,那么代码为:
Criteria criteria =session.createCriteria(Student.class);
Criterion criterion = Expression.like("name","王%");
这样还看不出来.那我们把检索条件加上年龄为22.
HQL:
String hql = "from Student s where s.name like '王%' and s.age= 22 ";
Query query = session.createQuery(hql);
List list = query.list();
QBC:
Criteria criteria =session.createCriteria(Student.class);
Criterion criterion1 = Expression.like("name","王%");
Criterion criterion2 = Expression.eq("age",newInteger(22));
criteria.add(criterion1).add(criterion2);
List list = criteria.list();


看上去烦琐很多.但是做过项目的人都知道,当一个模块业务逻辑发生改变的时候,往往要重写sql,最烦也是最讨厌的就是拿着别人的hql或者sql,两眼瞪的溜园找到底要修改什么地方呢?
如果使用QBC大大的增加了代码的可读性,以及可维护性.
需要注意的是null值
比如我们要查找姓名为null的Student对象时应该这么写
Criteria criteria =session.createCriteria(Student.class);
Criterion criterion = Expression.isNull("name");
criteria.add(criterion).list();
以及使用between...and的时候
Criteria criteria =session.createCriteria(Student.class);
Criterion criterion1 = Expression.ge("age",new Integer(20));//下限
Criterion criterion2 = Expression.le("age",new Integer(25));//上限
//这里也可以把上述两个条件添加到第三个条件里
Criterion criterion3 =Expression.and(criterion1,criterion2);
criteria.add(criterion3).list();
相当于from Student s where s.age between 20 and 25
等同于from Student s where s.age >= 20 and s.age <=25


下面是就HQL和QBC常用的查询条件做的比较
表达式含义                   HQL                   QBC
大于等于                     >=                    Expression.ge()
大于                         >                     Expression.gt()
小于等于                     <=                    Expression.le()
小于                         <                     Expression.lt()
等于                         =                     Expression.eq()
不等于                       <>或者!=              Expression.ne() 

为空                         is null               Expression.isNull()
不为空                       is notnull            Expression.isNotNull()
在指定范围内                 betweenand            Expression.between()
不在指定范围                 not betweenand        Expression.not(Expression.between())
属于某个集合                 in                    Expression.in()
不属于某个集合               notin                 Expression.not(Expression.in())
与                          and                   Expression.and()
或                          or                    Expression.or()
非                          not                   Expression.not()
模糊查询                    like                  Expression.like


1、创建一个Criteria实例 net.sf.hibernate.Criteria这个接口代表对一个特定的持久化类的查询。Session是用来制造Criteria实例的工厂。



Criteria crit = sess.createCriteria(Cat.class);


crit.setMaxResults(50);


List cats = crit.list();


2、缩小结果集范围 一个查询条件(Criterion)是net.sf.hibernate.expression.Criterion接口的一个实例。类net.sf.hibernate.expression.Expression定义了获得一些内置的Criterion类型。


List cats = sess.createCriteria(Cat.class)


                .add( Expression.like("name", "Fritz%") )


                .add( Expression.between("weight", minWeight, maxWeight))


                .list(); 

表达式(Expressions)可以按照逻辑分组.

 List cats = sess.createCriteria(Cat.class)



                .add( Expression.like("name", "Fritz%") )


                .add( Expression.or( Expression.eq( "age", new Integer(0) ), Expression.isNull("age")))


                .list();


List cats = sess.createCriteria(Cat.class)


                .add( Expression.in( "name",new String[]{"Fritz","Izi","Pk"}))


                .add( Expression.disjunction()


                .add( Expression.isNull("age") )


                .add( Expression.eq("age", new Integer(0) ) )


                .add( Expression.eq("age", new Integer(1) ) )


                .add( Expression.eq("age", new Integer(2) ) ) ) )


                 .list(); 

有很多预制的条件类型(Expression的子类)。有一个特别有用,可以让你直接嵌入SQL。

List cats = sess.createCriteria(Cat.class) 



                .add( Expression.sql("lower($alias.name) like lower(?)", "Fritz%", Hibernate.STRING))


                .list();  
其中的{alias}是一个占位符,它将会被所查询实体的行别名所替代。(原文:The {alias} placeholder with be replaced by the row alias of the queried entity.)


3、对结果排序 可以使用net.sf.hibernate.expression.Order对结果集排序.


List cats = sess.createCriteria(Cat.class)



                .add( Expression.like("name", "F%")


                .addOrder( Order.asc("name"))


                .addOrder( Order.desc("age"))


                .setMaxResults(50)


                .list();


4、关联(Associations) 你可以在关联之间使用createCriteria(),很容易地在存在关系的实体之间指定约束。


List cats = sess.createCriteria(Cat.class)



                 .add( Expression.like("name", "F%")


                 .createCriteria("kittens")


                 .add( Expression.like("name","F%")


                 .list();


注意,第二个createCriteria()返回一个Criteria的新实例,指向kittens集合类的元素。 下面的替代形式在特定情况下有用。


List cats = sess.createCriteria(Cat.class)


                .createAlias("kittens", "kt")


                .createAlias("mate", "mt")


                .add(Expression.eqProperty("kt.name", "mt.name"))


                .list();


(createAlias())并不会创建一个Criteria的新实例。) 请注意,前面两个查询中Cat实例所持有的kittens集合类并没有通过criteria预先过滤!如果你希望只返回满足条件的kittens,你必须使用returnMaps()。


List cats = sess.createCriteria(Cat.class)


 .createCriteria("kittens", "kt")


 .add( Expression.eq("name", "F%") )


 .returnMaps()


 .list();


Iterator iter = cats.iterator();


while ( iter.hasNext())


{  


 Map map = (Map) iter.next();


 Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);


 Cat kitten = (Cat) map.get("kt");



5、动态关联对象获取(Dynamic association fetching) 可以在运行时通过setFetchMode()来改变关联对象自动获取的策略。


List cats = sess.createCriteria(Cat.class)


                .add( Expression.like("name", "Fritz%") )


                .setFetchMode("mate", FetchMode.EAGER)


                .list();


这个查询会通过外连接(outer join)同时获得 mate和kittens。 


6、根据示例查询(Example queries) net.sf.hibernate.expression.Example类许你从指定的实例创造查询条件。


Cat cat = new Cat();


cat.setSex('F');


cat.setColor(Color.BLACK);


List results = session.createCriteria(Cat.class) 


                    .add( Example.create(cat) ) 


                    .list(); 
版本属性,表示符属性和关联都会被忽略。默认情况下,null值的属性也被排除在外。 You can adjust how the Example is applied. 你可
以调整示例(Example)如何应用。 Example example = Example.create(cat) .excludeZeroes() //exclude zero valued properties


.excludeProperty("color") //exclude the property named "color" .ignoreCase() //perform case insensitive string comparisons


.enableLike(); //use like for string comparisons


List results = session.createCriteria(Cat.class)


                      .add(example)


                      .list(); 
你甚至可以用示例对关联对象建立criteria。 List results = session.createCriteria(Cat.class) .add(Example.create(cat) )


.createCriteria("mate") .add(Example.create(cat.getMate())) .list();


参考代码如下:

[java] view plain copy
  1. String[] aa = new String[2];  
  2.   
  3.   
  4. List results = getSession().createCriteria(  
  5.         "base.database.entity.Menu")  
  6.         .add(Example.create(instance))  
  7.         .add(Restrictions.between("date",new Date(),new Date()))  
  8.         .add(Restrictions.or(Expression.eq("flg""S"), Expression.eq("FLG""D")))  
  9.         .add(Restrictions.in("flg", aa))  
  10.         .addOrder(Order.asc("menuOrder"))  
  11.         .list();  
  12.   
  13.   
  14. add(Projections.groupProperty("color"))  




一、基本使用

1. 说明

Restrictions 是产生查询条件的工具类。

2. 定义

可以直接用class 创建

DetachedCriteria searDc =

DetachedCriteria.forClass(QymlPerson.class);

也可以用hibernate session 创建

session.createCriteria(Student.class)

3. 条件查询

3.1 多条件的and 规则

通过searDc.add(Restrictions.eq("unid", userid))实现条件查询。

多次添加的条件,默认的规则是and.

3.2 多条件的or 规则

如果实现or 的查询,需要按照如下方式进行

searDc.add(Restrictions.or(Restrictions.eq("deptunid", "aa"),

Restrictions.isNull("deptunid")));

其中isnull 表示一个常规字段是否为空,isEmpty 用来表示一个集合字段是否为空。

4. 查询排序

通过searDc.addOrder(Order.asc(propertyName1))可以添加排序,如果有多个排

序字段,可以添加多次;最终的结果将按照添加的次序进行排序处理。

二、子查询

//主查询:人员查询

DetachedCriteria searDc =

DetachedCriteria.forClass(QymlPerson.class);

//子查询:职务人员关系表

DetachedCriteria sub =

DetachedCriteria.forClass(QymlPositionUserLink.class);

sub.add(Restrictions.eq("positionunid", positionunid));

//子查询:指定查询的列(也就是select usernuid from ....)

sub.setProjection(Property.forName("userunid"));

//主查询和子查询关联(也就是where unid in (select userunid from...) )

searDc.add(Property.forName("unid").in(sub));

在上面的例子中,用个一个类似于下面SQL 的子查询

Select * from Person a where a.unid in (select userunid from PositionUserLink b where

b.positionunid = ..)

Property 还有其他的条件判断,参考api

http://docs.jboss.org/hibernate/core/3.3/api/org/hibernate/criter

ion/Property.html

三、Restrictions表达式

HQL运算符 QBC运算符 含义

= Restrictions.eq() 等于equal

<> Restrictions.ne() 不等于 not equal

> Restrictions.gt() 大于greater than

>= Restrictions.ge() 大于等于 greater than or

equal

< Restrictions.lt() 小于less than

<= Restrictions.le() 小 于 等 于 less than or

equal

is null Restrictions.isnull() 等于空值

is not null Restrictions.isNotNull() 非空值

like Restrictions.like() 字符串模式匹配

and Restrictions.and() 逻辑与

and Restrictions.conjunction() 逻辑与

or Restrictions.or() 逻辑或

or Restrictions.disjunction() 逻辑或

not Restrictions.not() 逻辑非

in(列表) Restrictions.in() 等于列表中的某一个值

not in(列表) Restrictions.not(Restrictions.in()) 不等于列表中任意一个值

between x and y Restrictions.between() 闭区间 xy中的任意值

not between x and y

Restrictions.not(Restrictions..between()) 小于值X 或者大于值y

三、Restrictions关联查询

如果每个美女都有自己的客户资源(不要想歪了!),那么需要查询拥有客户Gates的美女怎么办?

使用Criteria可以有两种方法:

1:
DetachedCriteria beautyCriteria = DetachedCriteria.forClass(Beauty.class).createCriteria("customers");
beautyCriteria.add(Restrictions.eq("name", "Gates")):

2:
DetachedCriteria beautyCriteria = DetachedCriteria.forClass(Beauty.class).createAlias("customers", "c");
beautyCriteria.add(Restrictions.eq("c.name", "Gates")):

接着有了新的要求,年纪太大的美女不要,还是查找拥有客户Gates的,条件如下:
DetachedCriteria beautyCriteria = DetachedCriteria.forClass(Beauty.class, "b").;
DetachedCriteria customerCriteria = beautyCriteria.createAlias("customers", c");
beautyCriteria.add(Restrictions.le("b.age", new Long(20))):
customerCriteria.add(Restrictions.eq("c.name", "Gates")):


四.离线查询和子查询

条件查询的离线查询由DetachedCriteria来代表,DetachedCriteria类允许在一个Session范围之外创建一个查询,并且可以使用任意Session来执行它;

使用DetachedCriteria来执行离线查询,通常使用如下的方法来获得一个离线查询:

//创建指定持久化类的离线查询

DetachedCriteria.forClass(Class entity)

除此之外,DetachedCriteria还可代表子查询,当把DetachedCriteria传入Criteria中作为查询条件时,DetachedCriteria就变成了子查询,条件实例包含子查询通过Subqueries或者Property来获得;

如下程序示范了使用DetachedCriteria进行离线查询和子查询:

离线查询:

[java] view plain copy
 print?
  1. <span style="font-size:18px;"><strong>  public void Query(){  
  2.         //定义一个离线查询  
  3.         DetachedCriteria query = DetachedCriteria.forClass(Student.class)  
  4.                 .setProjection(Property.forName("name"));  
  5.         //打开Session和事务  
  6.         Session sess = HibernateSessionFactory.getSession();  
  7.         Transaction tx = sess.beginTransaction();  
  8.         //执行离线查询  
  9.         List list = query.getExecutableCriteria(sess).list();  
  10.         for(Object obj:list){  
  11.             System.out.println(obj);  
  12.         }  
  13.         tx.commit();  
  14.         HibernateSessionFactory.closeSession();  
  15.     }</strong></span>  
子查询:

[java] view plain copy
 print?
  1. <span style="font-size:18px;"><strong>  public void Query(){  
  2.         //定义一个离线查询  
  3.         DetachedCriteria query = DetachedCriteria.forClass(Student.class)  
  4.                 .setProjection(Property.forName("name"));  
  5.         //打开Session和事务  
  6.         Session sess = HibernateSessionFactory.getSession();  
  7.         Transaction tx = sess.beginTransaction();  
  8.         //执行子查询  
  9.         List<Student> list = sess.createCriteria(Student.class)  
  10.                 //下面两行代码作用相同,都示范了通过子查询添加查询条件  
  11.                 //.add(Property.forName("name").in(query))  
  12.                 .add(Subqueries.propertyIn("name", query))  
  13.                 .list();  
  14.         for(Student obj:list){  
  15.             System.out.println(obj.getName());  
  16.         }  
  17.         tx.commit();  
  18.         HibernateSessionFactory.closeSession();  
  19.     }</strong></span>  
从上面的程序来看,当创建一个DetachedCriteria对象之后,该对象到底被作为离线查询使用还是作为子查询使用,都与DetachedCriteria无关;

如果程序使用Session的getExecutableCriteria()方法来执行DetachedCriteria对象,则他被当成离线查询使用,如果程序使用Property(或Subqueries的系列类方法)来操作DetachedCriteria对象,则他被当作子查询使用;

Property类提供了eq()、eqAll、ge()、geAll()、gt()、gtAll()、in等系列方法,这些方法与SQL子查询中的运算符一一对应,除此之外,Subqueries也提供了eq()、eqAll、ge()、geAll()、gt()、gtAll()、in等静态方法,这些方法与Property同名的实例方法的功能基本相似,在这种情况下,DetachedCriteria被当成子查询使用;

-----------------------------------------------------------------

补充1:

[java] view plain copy
 print?
  1. public static void query(){  
  2.     Session sess = HibernateSessionFactory.getSession();  
  3.     Transaction tx = sess.beginTransaction();  
  4.     Criteria criteria = sess.createCriteria(User.class,"user");  
  5.     criteria.createCriteria("institution","institution");  
  6.     ProjectionList pList = Projections.projectionList();  
  7.     pList.add(Property.forName("user.id").as("aa"))  
  8.         .add(Projections.property("user.username").as("bb"))  
  9.         .add(Projections.property("institution.institutionName").as("cc"));  
  10.     criteria.setProjection(pList);  
  11.     criteria.setResultTransformer(Transformers.aliasToBean(Temp.class));  
  12.     List list = criteria.list();   
  13.     tx.commit();  
  14.     HibernateSessionFactory.closeSession();  
  15. }  

这个方法的含义是:

1>查询User类的指定字段;

2>查处的结果使用setResultTransformer方法进行规整,必须有一个Temp的类去接收指定的字段,如下:

[java] view plain copy
 print?
  1. package com.anlw.entity;  
  2.   
  3. public class Temp {  
  4.     private int aa;  
  5.     private String bb;  
  6.     private String cc;  
  7.     public int getAa() {  
  8.         return aa;  
  9.     }  
  10.     public void setAa(int aa) {  
  11.         this.aa = aa;  
  12.     }  
  13.     public String getBb() {  
  14.         return bb;  
  15.     }  
  16.     public void setBb(String bb) {  
  17.         this.bb = bb;  
  18.     }  
  19.     public String getCc() {  
  20.         return cc;  
  21.     }  
  22.     public void setCc(String cc) {  
  23.         this.cc = cc;  
  24.     }  
  25.       
  26. }  



0 0
原创粉丝点击