Hibernate中Criteria的完整用法【整理】

来源:互联网 发布:如何制作自己的软件 编辑:程序博客网 时间:2024/05/22 10:38

QBE (Query By Example)
Criteria cri = session.createCriteria(Student.class);
cri.add(Example.create(s)); //s是一个Student对象
list cri.list();

net.sf.hibernate.expression.Example类允许你从指定的实例创造查询条件。
实质:创建一个模版,比如我有一个表serial有一个 giftortoy字段,我设置serial.setgifttoy("2"),
则这个表中的所有的giftortoy为2的数据都会出来

QBC (Query By Criteria) 主要有Criteria,Criterion,Oder,Restrictions类组成
session = this.getSession();
Criteria cri = session.createCriteria(JdItemSerialnumber.class);
Criterion cron = Restrictions.like("customer",name);
cri.add(cron);
list = cri.list();

Criteria接口表示特定持久类的一个查询
Criteria criteria = session.createCriteria(User.class);
List users = criteria.list();
Criteria建立后,若不给予任何的条件,预设是查询物件所对应表格之所有资料,

Criteria实际上是个条件附加的容器,如果想要设定查询条件,则要使用Restrictions的各种静态方法传回Criteria实例,传回的每个Criteria实例代表着一个条件,您要使用Criteria的add()方法加入这些条件实例,
例如查询”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();

Criterion 是 Criteria 的查询条件。Criteria 提供了 add(Criterion criterion) 方法来添加查询条件。
Criterion 接口的主要实现包括: Example 、 Junction 和 SimpleExpression 。
Junction 的实际使用是它的两个子类 conjunction 和 disjunction ,分别是使用 AND 和 OR 操作符进行来联结查询条件集合。

Criterion 的实例可以通过 Restrictions 工具类来创建,Restrictions 提供了大量的静态方法,如 eq (等于)、 ge (大于等于)、 between 等来方法的创建 Criterion 查询条件(SimpleExpression 实例)。除此之外, Restrictions 还提供了方法来创建 conjunction 和disjunction 实例,通过往该实例的 add(Criteria) 方法来增加查询条件形成一个查询条件集合。如果有and或者是or的关系的话,可以使用Conjunction(AND)和Disjunction(OR)!

至于 Example 的创建有所不同, Example 本身提供了一个静态方法 create(Objectentity) ,即根据一个对象(实际使用中一般是映射到数据库的对象)来创建。然后可以设置一些过滤条件:
Example exampleUser =Example.create(u).ignoreCase().enableLike(MatchMode.ANYWHERE);

Project 主要是让 Criteria 能够进行报表查询,并可以实现分组。 Project 主要有 
SimpleProjection 、 ProjectionList 和 Property 三个实现。其中 SimpleProjection 和 
ProjectionList 的实例化是由内建的 Projections 来完成,如提供的 avg 、 count 、 max 、 
min 、 sum 可以让开发者很容易对某个字段进行统计查询。 

Property 是对某个字段进行查询条件的设置,如通过Porperty.forName(“color”).in (new String[]{“black”,”red”,”write”}); 则可以创建一个 Project 实例。通过criteria 的 add(Project) 方法加入到查询条件中去。 

Expression.eq 对应SQL“field = value”表达式。 如Expression.eq("name","Erica")
Expression.allEq 参数为一个Map对象,其中包含了多个属性-值对应关系。相当于多个Expression.eq关系的叠加。
Expression.gt 对应SQL中的 “field > value ” 表达式
Expression.ge 对应SQL中的 “field >= value” 表达式
Expression.lt 对应SQL中的 “field < value” 表达式
Expression.le 对应SQL中的 “field <= value” 表达式
Expression.between 对应SQL中的 “between” 表达式
方法 说明
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限定查询

Property实例是获得一个条件的另外一种途径。你可以通过调用Property.forName() 创建一个 Property。
Property age = Property.forName("age"); 
List cats = sess.createCriteria(Cat.class) 
    .add( Restrictions.disjunction() 
        .add( age.isNull() ) 
        .add( age.eq( new Integer(0) ) ) 
        .add( age.eq( new Integer(1) ) ) 
        .add( age.eq( new Integer(2) ) ) 
    ) ) 
    .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) ) 
    .list(); 

使用Criteria进行查询时,不仅仅能组合出SQL中where子句的功能,还可以组合出如排序、统计、分组等的查询功能。

Criteria crit = session.createCriteria(Conft.class); 
// 创建条件 
Criterion a = Restrictions.gt("id", 2); // > 
Criterion b = Restrictions.lt("id", 2); // < 
Criterion c = Restrictions.like("id", "2",MatchMode.ANYWHERE); 
// and 关系 
Conjunction conjunction = Restrictions.conjunction(); 
conjunction.add(a); 
conjunction.add(b); 
// or 关系 
Disjunction disjunction = Restrictions.disjunction(); 
disjunction.add(conjunction); 
disjunction.add(c);  
// 增加查询条件 
crit.add(disjunction);   
List<Conft> list = crit.list(); 

除此之外还可以使用sqlRestriction方法直接拼接SQL
public User getUserById(int pk){ 
    Session session = this.getSession(); 
    Criteria crit = session.createCriteria(User.class); 
    crit.add(Restrictions.sqlRestriction(" {alias}.id=2 ")); 
    List<User> list = crit.list(); 
    return (User)list.get(0); 

 
注意{alias}是表的名称,这个不用修改,Hibernate在生成SQL时会自动替换!
Expression.sql 作为补充,本方法提供了原生SQL语法的支持。我们可以通过这个方法直接通过SQL语句限定查询条件。
List cats = sess.createCriteria(Cat.class) 
    .add( Restrictions.sql("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) ) 
    .list(); 

结果集排序 
你可以使用org.hibernate.criterion.Order来为查询结果排序。 
List cats = sess.createCriteria(Cat.class) 
    .add( Restrictions.like("name", "F%") 
    .addOrder( Order.asc("name") ) 
    .addOrder( Order.desc("age") ) 
    .setMaxResults(50) 
    .list(); 

List cats = sess.createCriteria(Cat.class) 
    .add( Property.forName("name").like("F%") ) 
    .addOrder( Property.forName("name").asc() ) 
    .addOrder( Property.forName("age").desc() ) 
    .setMaxResults(50) 
    .list(); 

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();

限定查询笔数
Criteria的setMaxResults()方法可以限定查询回来的笔数,如果配合setFirstResult()设定传回查询结果第一笔资料的位置,就可以实现简单的分页,例如传回第51笔之后的50笔资料(如果有的话):
Criteria criteria = session.createCriteria(User.class);
criteria.setFirstResult(51);
criteria.setMaxResults(50);
List users = criteria.list();

根据您所指定得资料库,Hibernate将自动产生与资料库相依的限定笔数查询子句,例如在MySQL中,将使用limit产生以下的SQL语句:
Hibernate: select this_.id as id0_0_, this_.name as name0_0_, this_.age as age0_0_ from T_USER this_ limit ?, ?

统计动作
您可以对查询结果进行统计动作,使用org.hibernate.criterion.Projections的avg()、rowCount()、count()、max()、min()、 countDistinct()等方法,再搭配Criteria的setProjection()方法加入条件设定,例如对查询结果的"age"作平均:
Criteria criteria = session.createCriteria(User.class);
criteria.setProjection(Projections.avg("age"));
List users = criteria.list();

上面的程式将由Hibernate自动产生SQL的avg函数进行平均计算:
Hibernate: select avg(this_.age) as y0_ from T_USER this_

分组
还可以配合Projections的groupProperty()来对结果进行分组,例如以"age"进行分组,也就是如果资料中"age"如果有 20、20、25、30,则以下会显示20、25、30:
Criteria criteria = session.createCriteria(User.class);
criteria.setProjection(Projections.groupProperty("age"));
List users = criteria.list();

上面的程式将由Hibernate自动产生SQL的group by子句进行分组计算:
Hibernate: select this_.age as y0_ from T_USER this_ group by this_.age

如果想同时结合统计与分组功能,则可以使用org.hibernate.criterion.ProjectionList,例如下面的程式会计算每个年龄各有多少个人:
ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.groupProperty("age"));
projectionList.add(Projections.rowCount());

Criteria criteria = session.createCriteria(User.class);
criteria.setProjection(projectionList);
List users = criteria.list();

观察所产生的SQL语句,将使用group by先进行分组,再针对每个分组进行count函数的计数
Hibernate: select this_.age as y0_, count(*) as y1_ from T_USER this_ group by this_.age

根据已知物件进行查询
设定查询条件并非一定要使用Restrictions,如果属性条件很多,使用Restrictions也不方便,如果有一个已知的物件,则可以根据这个物件作为查询的依据,看看是否有属性与之类似的物件,例如:
User user = new User();
user.setAge(new Integer(30));

Criteria criteria = session.createCriteria(User.class);
criteria.add(Example.create(user));
List users = criteria.list();

您可以透过org.hibernate.criterion.Example的create()方法来建立Example实例,Example实作了Criteria介面,因此可以使用add()方法加入至Criteria条件设定之中,Hibernate将自动过滤掉空属性,根据已知物件上已设定的属性,判定是否产生于where子句之中:
Hibernate: select this_.id as id0_0_, this_.name as name0_0_, this_.age as age0_0_ from T_USER this_ where (this_.age=?)

使用DetchedCriteria
Criteria与Session绑定,其生命週期跟随着Session结束而结束,使用Criteria时进行查询时,每次都要于执行时期动态建立物件,并加入各种查询条件,随着Session的回收,Criteria也跟着回收。

为了能够重複使用Criteria物件,在Hibernate 3中新增了org.hibernate.criterion.DetchedCriteria,您可以先建立DetchedCriteria实例,并加入各种查询条件,并于需要查询时再与Session绑定,获得一个绑定Session的Criteria物件,例如:
// 先建立DetchedCriteria物件
DetachedCriteria detchedCriteria = DetachedCriteria.forClass(User.class);
// 加入查询条件
detchedCriteria.add(Restrictions.ge("age",new Integer(25)));

Session session = sessionFactory.openSession();
// 绑定Session并返回一个Criteria实例
Criteria criteria = detchedCriteria.getExecutableCriteria(session);
List users = criteria.list();

Criteria 和 DetachedCriteria 的主要区别在于创建的形式不一样, Criteria 是在线的,所以它是由 Hibernate Session 进行创建的;而 DetachedCriteria 是离线的,创建时无需 Session,DetachedCriteria 提供了 2 个静态方法 forClass(Class) 或 forEntityName(Name) 进行DetachedCriteria 实例的创建。spring 的框架提供了getHibernateTemplate().findByCriteria(detachedCriteria) 方法可以很方便地根据DetachedCriteria 来返回查询结果。 
Criteria 和 DetachedCriteria 均可使用 Criterion 和 Projection 设置查询条件。可以设置 FetchMode( 联合查询抓取的模式 ) ,设置排序方式。对于 Criteria 还可以设置 FlushModel (冲刷 Session 的方式)和 LockMode (数据库锁模式)。 

关联 
你可以使用createCriteria()非常容易的在互相关联的实体间建立 约束。 
List cats = sess.createCriteria(Cat.class) 
    .add( Restrictions.like("name", "F%") 
    .createCriteria("kittens") 
    .add( Restrictions.like("name", "F%") 
    .list(); 

注意第二个 createCriteria()返回一个新的 Criteria实例,该实例引用kittens 集合中的元素。 
接下来,替换形态在某些情况下也是很有用的。 
List cats = sess.createCriteria(Cat.class) 
    .createAlias("kittens", "kt") 
    .createAlias("mate", "mt") 
    .add( Restrictions.eqProperty("kt.name", "mt.name") ) 
    .list(); 

(createAlias()并不创建一个新的 Criteria实例。) Cat实例所保存的之前两次查询所返回的kittens集合是没有被条件预过滤的。
如果你希望只获得符合条件的kittens, 你必须使用returnMaps()。 
List cats = sess.createCriteria(Cat.class) 
    .createCriteria("kittens", "kt") 
    .add( Restrictions.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"); 


如果你希望只获得符合条件的kittens, 你必须使用ResultTransformer。 
List cats = sess.createCriteria(Cat.class)
   .createCriteria("kittens", "kt")
   .add( Restrictions.eq("name", "F%") )
   .setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
   .list();

动态关联抓取 
你可以使用setFetchMode()在运行时定义动态关联抓取的语义。 
List cats = sess.createCriteria(Cat.class) 
    .add( Restrictions.like("name", "Fritz%") ) 
    .setFetchMode("mate", FetchMode.EAGER) 
    .setFetchMode("kittens", FetchMode.EAGER) 
    .list(); 

org.hibernate.criterion.Example类允许你通过一个给定实例构建一个条件查询。版本属性、标识符和关联被忽略。
默认情况下值为null的属性将被排除。
你可以自行调整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();

你甚至可以使用examples在关联对象上放置条件。
List results = session.createCriteria(Cat.class)
.add( Example.create(cat) )
.createCriteria("mate")
.add( Example.create( cat.getMate() ) )
.list();

投影(Projections)、聚合(aggregation)和分组(grouping) 
org.hibernate.criterion.Projections是 Projection 的实例工厂。我们通过调用setProjection()应用投影到一个查询。 
List results = session.createCriteria(Cat.class) 
    .setProjection( Projections.rowCount() ) 
    .add( Restrictions.eq("color", Color.BLACK) ) 
    .list(); 

List results = session.createCriteria(Cat.class) 
    .setProjection( Projections.projectionList() 
  .add( Projections.rowCount() ) 
    .add( Projections.avg("weight") ) 
    .add( Projections.max("weight") ) 
    .add( Projections.groupProperty("color") ) 
    ) 
    .list(); 

在一个条件查询中没有必要显式的使用 "group by" 。某些投影类型就是被定义为 分组投影,他们也出现在SQL的group by子句中。 
可以选择把一个别名指派给一个投影,这样可以使投影值被约束或排序所引用。
下面是两种不同的实现方式: 
List results = session.createCriteria(Cat.class) 
    .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) ) 
    .addOrder( Order.asc("colr") ) 
    .list(); 

List results = session.createCriteria(Cat.class) 
    .setProjection( Projections.groupProperty("color").as("colr") ) 
    .addOrder( Order.asc("colr") ) 
    .list();

原创粉丝点击