1. 程式人生 > >hibernate Criteria QBC查詢

hibernate Criteria QBC查詢

QBC查詢:

   QBC查詢就是通過使用Hibernate提供的Query By Criteria API來查詢物件,這種API封裝了SQL語句的動態拼裝,對查詢提供了更加面向物件的功能介面。我們看下面的示例程式:

Criteria criteria=session.createCriteria(User.class);

criteria.add(Expression.eq(“name”,”zx”));

criteria.add(Expression.eq(“age”,new Integer(27));

List list=criteria.list();

當執行criteria.list()時會生成類似這樣的SQL語句:Select * from user where name=’zx’ and age=27;所以在這裡我們可以看出,Criteria實際上是一個查詢容器,它對查詢條件表示式的新增進行了封裝,具體的查詢條件是通過add()方法新增的,而且具體的查詢條件的表示式運算是通過Expression指定的。Hibernate在執行期會根據Criteria指定的表示式條件來新增查詢條件,並且生成查詢語句。這種方式非常符合Java以及所有面向物件程式語言的程式設計方式,所以大多數的持久層框架都提供了對這種方式查詢的支援。下面我們講解這種查詢方式的各個技術細節。

1、Criteria查詢表示式:

正如我們所見,Expression對查詢語句的表示式進行了封裝和限制,下表列出了Expression所有的方法,以及每個方法所對應的查詢表示式及其限制。

方法 描述
Expression.eq

對應SQL的“field=value”表示式

如:Expression.eq(“name”,”zx”);

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表示式,如:查詢年齡在21與27歲之間的使用者,可以寫成Expression.between(“age”,new Integer(21),new Integer(27));
Expression.like 對應SQL語句的”field like value”表示式
Expression.in 對應SQL語句的“field in(……)”表示式
Expression.eqProperty 用於比較兩個屬性值,對應”field=field”SQL表示式
Expression.gtProperty 用於比較兩個屬性值,對應”field>field”SQL表示式
Expression.geProperty 用於比較兩個屬性值,對應”field>=field”SQL表示式
Expression.ltProperty 用於比較兩個屬性值,對應”field<field”SQL表示式
Expression.leProperty 用於比較兩個屬性值,對應”field<=field”SQL表示式
Expression.and 對應SQL語句的And關係組合,如:Expression.and(Expression.eq(“name”,”zx”),Expression.eq(“sex”,”1”));
Expression.or 對應SQL語句的Or關係組合,如:Expression.or(Expression.eq(“name”,”zx”),Expression.eq(“name”,”zhaoxin”));
Expression.sql 作為補充這個方法提供了原生SQL語句查詢的支援,在執行時直接通過原生SQL語句進行限定,如:Expression.sql(“lower({alias}.name) like (?)”,“zhao%”,Hibernate.STRING) ;在執行時{ alias }將會由當前查詢所關聯的實體類名替換,()中的?將會由”zhao%”替換,並且型別由Hibernate.STRING指定。

注意:Expression各方法中的屬性引數(各方法中的第一個引數)所指定的屬性名稱(如:name,sex),並不是資料庫表中的實際欄位名稱,而是實體物件中對映實際資料表字段的類屬性名稱。

 

2、示例查詢:

   示例查詢是通過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<list.size();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判斷語句。

3、複合查詢:

複合查詢主要是處理,具有關聯關係的兩個實體怎樣進行關聯查詢,比如User實體物件與Addres實體物件具有一對多的關聯關係,我們可以如下構造符合查詢:

Criteria criteria=session.createCriteria(User.class);

   Criteria addcriteria=criteria.createCriteria(“addresses”);(1)

   addcriteria.add(Express.like(“address”,”%tianjin%”));

  List list=criteria.list();

   for(int i=0;i<list.size();i++){

     User user=(User)list.get(i);

     System.out.println(user.getName()+”\n”);

     Set addresses=user.getAddresses();

     Iterator it=addresses.iterator();

     while(it.hasNext(){

      Address address=(Address)it.next();

      System.out.println(address.getAddress()+”\n”);

     }

   }

當執行到了(1)處時,表明要針對User物件的addresses屬性新增新的查詢條件,因此當執行criteria.list()時,Hibernate會生成類似如下的SQL語句:

Select * from user inner join address on user.id=address.id where address.address like ‘%shanghai%’;

正如我們所見,我們可以通過向Criteria中新增儲存關聯物件的集合屬性(addresses屬性儲存與User物件相關聯的Address物件),來構造複合查詢,在資料庫一端是通過內連線查詢來實現。

 

 

 

4、Criteria的高階特性:

A、限定返回記錄條數:

 我們可以通過利用Criteria.setFirstResult/setMaxResult方法來限定返回某一次查詢的記錄數,如下程式碼:

Criteria criteria=session.createCriteria(User.class);

criteria.setFirstResult(100);

criteria.setMaxResult(200);

通過以上程式碼可以設定該次查詢返回user表中的從第100條記錄開始直到第200條記錄結束的100條記錄。

B、對查詢結果進行排序:

 可通過使用net.sf.hibernate.expression.Order類可以對查詢結果集進行排序,如下面程式碼:

Criteria criteria=session.createCriteria(User.class);

criteria.add(Expression.eq(“groupid”,”2”);

criteria.addOrder(Order.asc(“name”));

criteria.addOrder(Order.desc(“groupid”));

List list=criteria.list();

通過使用Order類的asc()/desc()方法,可以指定針對某個欄位的排序邏輯,如果執行上述程式碼,會生成類似如下的SQL語句:

Select * from user where groupid=’2’ order by name asc,groupid desc

C、分組與統計:

   在Hibernate3中,對Criteria又增添了新功能,可以支援分組與統計功能,在Hibernate3中增加了Projections以及ProjectionList類,這兩個類對分組與統計功能進行了封裝,如下程式碼:

Criteria criteria=session.createCriteria(User.class);

criteria.setProjection(Projections.groupProperty(“age”));(1)

List list=criteria.list();

Iterator it=list.iterator();

while(it.hasNext()){

 System.out.println(it.next());

}

通過(1)處的程式碼,我們通過Projections類指定了用於分組的目標屬性,當進行檢索時Hibernate會生成類似如下的SQL語句:

Select age from user group by age;

還可以通過使用Projections的avg()/rowCount()/count()/max()/min()/countDistinct()等方法來實現統計功能,如下面的程式碼示例:

Criteria criteria=session.createCriteria(User.class);

criteria.setProjection(Projections.avg(“age”));(1)

List list=criteria.list();

Iterator it=list.iterator();

while(it.hasNext()){

 System.out.println(it.next());

}

通過(1)處的程式碼,我們實現了對使用者平均年齡的統計,當進行檢索時,Hibernate會生成類似如下的SQL語句:

Select avg(age) from user;

另外,在SQL語句中的多條件分組與統計功能,可以利用ProjectionList類來實現,如下面程式碼所示:

Criteria criteria=session.createCriteria(User.class);

ProjectionList prolist=Projections.projectionList();

prolist.add(Projections.groupProperty(“age”));

prolist.add(Projections.rowCount());

criteria.setProjection(prolist);

List list=criteria.list();

通過以上程式碼,實現了對不同年齡人員數量的分組統計,當進行檢索時,Hibernate會生成類似如下的SQL語句:

Select age,count(*) from user group by age;

5、DetachedCriteria:

在Hibernate2中,Criteria例項是與建立它的Session例項具有相同的生命週期的,也就是說,Session例項是它所建立的Criteria例項的宿主,當Session關閉時,寄生於Session例項的Criteria都將失效。這就對Criteria的重用造成了困難,為了實現Criteria例項的重用,在Hibernate3中提供了一個DetachedCriteria類,DetachedCriteria例項的生命週期與Session例項的生命週期無關,我們可以利用DetachedCriteria對一些常用的Criteria查詢條件進行抽離,當需要進行檢索時再與Session例項關聯,從而獲得執行期的Criteria例項。如下面的程式碼所示:

   DetachedCriteria dc= DetachedCriteria.forClass(User.class);

   dc.add(Expression.eq(“name”,”zhaoxin”));

   dc.add(Expression.eq(“sex”,”1”));

   Criteria criteria=dc.getExecutableCriteria(session);

   Iterator it=criteria.list().iterator();

   while(it.hasNext()){

     User user=(User)it.next();

     System.out.println(user.getName());

   }

 正如我們所見,DetachedCriteria的生存週期與session例項無關,當需要進行檢索時,通過getExecutableCriteria(session)方法,與當前的Session例項關聯並獲得執行期的Criteria例項,完成檢索。

DetachedCriteria也可以用於完成子查詢功能,如下程式碼所示:

DetachedCriteria dc= DetachedCriteria.forClass(User.class);

dc.setProjection(Projections.avg(“age”));

Criteria criteria=session.createCriteria(User.class);

criteria.add(Subqueries.propertyGt(“age”,dc));

List list=criteria.list();

通過Subqueries類,實現了新增子查詢的功能,我們將DetachedCriteria所設定的查詢條件,當作子查詢新增到了執行時Criteria例項的查詢條件中,當執行檢索時Hibernate會生成類似如下的SQL語句:

Select * from user where age>(select avg(age) from user group by age);

 

Hibernate除了處理查詢結果集中的物件之外,還可以將結果集中的結果當做行和列集來使用,這與通過JDBC執行select查詢獲得的資料的使用方式相似。因此,Hibernate也支援屬性、統計函式和Group By等查詢。

要想使用Hibernate的投影統計功能,首先要從org.hibernate.criterion.Projections工廠類獲得org.hibernate.criterion.Projection物件。與Restrictions類相似,Projections類提供了幾個用來獲取Projection例項的靜態工廠方法。在獲得Projection物件之後,使用setProjection()方法將它新增到Criteria物件中。注意,返回的結果集是Object型別,需要對結果進行適當的型別轉換。