Hibernate的DetachedCriteria使用(含Criteria)

Hibernate总的来说共有三种查询方式:HQL、QBC和SQL三种

HQL(Hibernate Query Language)

SQL(Structured Query Language)

QBC(Query By Criteria)

今天重点介绍QBC

这种方式比较面向对象方式,重点是有三个描述条件的对象:Restrictions,Order,Projections。使用QBC查询,一般需要以下三个步骤

  1. 使用Session实例的createCriteria()方法创建Criteria对象;
  2. 使用工具类Restrictions的方法为Criteria对象设置查询条件,Order工具类的方法设置排序方式,Projections工具类的方法进行统计和分组;
  3. 使用Criteria对象的list()方法进行查询并返回结果。

Restrictions、Order、Projections的常用方法

Restrictions类的常用方法(设置查询条件):

返回值类型 方法名称 描述
SimpleExpression Restrictions.eq 等于(equal)
Criterion Restrictions.allEq 使用Map,Key/Valu进行多个等于的比对
SimpleExpression Restrictions.gt 大于(great than)
SimpleExpression Restrictions.ge 大于等于(great than or equal)
SimpleExpression Restrictions.lt 小于(less than)
SimpleExpression Restrictions.le 小于等于(less than or equal)
Criterion Restrictions.between 对应SQL的between
SimpleExpression Restrictions.like 对应SQL的like
Criterion Restrictions.in 对应SQL的in
LogicalExpression Restrictions.and and关系
LogicalExpression Restrictions.or or关系
Criterion Restrictions.isNull 为空
Criterion Restrictions.sqlRestriction SQL限定查询

 

Order类的常用方法(设置排序方式):

返回值类型 方法名称 描述
Order Order.asc 升序
Order Order.desc 降序

 

Projections类的常用方法(统计和分组):

返回值类型 方法名称 描述
AggregateProjection Projections.avg 求平均值
CountProjection Projections.count 统计某属性的数量
CountProjection Projections.countDistinct 统计某属性不同值的数量
PropertyProjection Projections.groupProperty 指定某个属性为分组属性
AggregateProjection Projections.max 求最大值
AggregateProjection Projections.min 求最小值
ProjectionList Projections.projectionList 创建一个ProjectionList对象
Projection Projections.rowCount 查询结果集中的记录条数
AggregateProjection Projections.sum 求某属性的合计

 

QBC的查询示例和基本理解

查询历史记录表中的供应商数据

private void getEQDetachedCriteria(Class clasz){
   Criteria criteria =getCurrentSession().createCriteria(VenAllHistory.class);
   criteria.add(Restrictions.eq("PointerType","Vendor"));
   criteria.addOrder(Order.desc("HistoryId"));
   ///分页查询前10条
   criteria.setFirstResult(0);
   criteria.setMaxResults(10);
   criteria.list();
}

 

复合查询

复合查询就是在原有的查询基础上在进行查询,比如有Clazz班级,包含对象属性Student,那么我们希望查询 “包含学生姓名为Bob” 的班级,那么就可以使用复合查询:

Criteria criteria = session.createCriteria(Clazz.class);Criteria criteriaInner = criteria.createCriteria(Student.class);
criteriaInner.add(Restrictions.eq("name", "Bob"));
List clazzList =  criteria.list();

DetachedCriteria、Criteria 使用区别

在常规的Web编程中,有大量的动态条件查询,即用户在网页上面自由选择某些条件,程序根据用户的选择条件,动态生成SQL语句,进行查询。
此时,我们不能在Web层使用Criteria,因为它是和Session绑定的。
DetachedCriteria可以解决这个问题,即在web层,程序员使用DetachedCriteria来构造查询条件,然后将这个 DetachedCriteria作为方法调用参数传递给业务层对象。而业务层对象获得DetachedCriteria之后,可以在session范围内直接构造Criteria,进行查询。就此,查询语句的构造完全被搬离到web层实现,而业务层则只负责完成持久化和查询的封装即可,与查询条件构造完全解耦,非常完美!

主要区别

父接口CriteriaSpecification,其下有子接口Criteria和实现类DetachedCriteria,Criteria和DetachedCriteria均可使用Criterion和Projection设置查询条件。可以设置FetchMode( 联合查询抓取的模式 ) ,设置排序方式。对于Criteria还可以设置FlushModel(冲刷 Session 的方式)和LockMode(数据库锁模式)。

Criteria和DetachedCriteria的主要区别在于创建的形式不一样,Criteria是在线的,所以它是由Hibernate Session进行创建的;而DetachedCriteria是离线的,创建时无需Session,它通过2个静态方法forClass(Class) 或 forEntityName(Name) 进行DetachedCriteria 的实例创建。

(另,Spring的框架提供了getHibernateTemplate ().findByCriteria(detachedCriteria) 方法可以很方便地根据DetachedCriteria来返回查询结果)

所以它也称为离线条件查询,即建立一个DetachedCriteria对象,将查询的条件等指定好,然后在session.beginTransaction()后将这个对象传入。通常这个对象可以在表示层建立,然后传入业务层进行查询。

 

private void getEQDetachedCriteria(Class clasz){
   DetachedCriteria criteria= DetachedCriteria.forClass(VenAllHistory.class);
   criteria.add(Restrictions.eq("PointerType","Vendor"));
   criteria.addOrder(Order.desc("HistoryId"));
   Session session = this.getCurrentSession();
   Criteria executableCriteria = criteria.getExecutableCriteria(session);
   executableCriteria.setCacheable(true);
   //return findByCriteria(criteria, -1, -1);
   return executableCriteria.list();
}

DetachedCriteria作为子查询

//主查询:人员查询
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 = ..)

 

动态关联抓取

我们的抓取模式,对于1对多的关联的形式!是不是抓取过来呢?
你可以使用setFetchMode()在运行时定义动态关联抓取的语义

List cats = sess.createCriteria(Cat.class)
    .add( Restrictions.like("name", "Fritz%") )
    .setFetchMode("mate", FetchMode.JOIN)
    .setFetchMode("kittens", FetchMode.JOIN)
    .list();

投影(Projections)、聚合(aggregation)和分组(grouping)

org.hibernate.criterion.Projections是 Projection 的实例工厂。 
我们通过调用setProjection()应用投影到一个查询。这个的意思就是查询哪一列的意思 
用来进行聚合操作,和sql中的聚合类似.求和/求平均值/统计记录数/…等等. 
还有用来获取获取对象的某些属性(表字段)或属性集合.正常情况下,查询返回的是对象或对象的集合.使用投影的话就可以只返回你需要的属性值.此时,即Hibernate不把记录封装对象了,只返回你在投影中设置的属性的值(值的集合)的数组

List results = session.createCriteria(Cat.class)
    .setProjection( Projections.projectionList()
        .add( Projections.rowCount() )
        //当你添加一个投影到一个投影列表中时 你可以为它指定一个别名:如
        //.add( Projections.rowCount() ,"count")
        .add( Projections.avg("weight") )
        .add( Projections.max("weight") )
        .add( Projections.groupProperty("color") )
    )
    .list();

可以选择把一个别名指派给一个投影,这样可以使投影值被约束或排序所引用。下面是两种不同的实现方式:

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

也可以使用Property.forName()来表示投影:

List results = session.createCriteria(Cat.class)
    .setProjection( Projections.projectionList()
        .add( Projections.rowCount().as("catCountByColor") )
        .add( Property.forName("name"))
        .add( Property.forName("weight").avg().as("avgWeight") )
        .add( Property.forName("weight").max().as("maxWeight") )
        .add( Property.forName("color").group().as("color" )
    )
    .addOrder( Order.desc("catCountByColor") )
    .addOrder( Order.desc("avgWeight") )
    .list();

 

 

 

 

 

你可能感兴趣的:(#,SSH之Hibernate)