Hibernate 中的 Criteria 查詢。

客戶提出建議讓我們使用hiberante中的criteria查詢代替hsql,既然客戶有這個要求,重新撿起來,網友寫了下面的文章,個人感覺不錯,重新排版,個人習慣Google Docs編輯,感覺比csdn的編輯器好用,以便日後翻閱!

 

文章重排版地址:http://docs.google.com/Doc?id=dfd33b53_33c86qfcdw

 

最近在項目中使用 Spring Hibernate 進行開發,有感於 Criteria 比較好用,在查詢方法,設計上可以靈活的根據 Criteria 的特點來方便地進行查詢條件的組裝。現在對 HibernateCriteria 的用法進行總結:

 


本文內容如下

 

 

 

 

 

0. 架構理解

   1)Criteria DetachedCriteria

 

       Hibernate 設計了 CriteriaSpecification 作爲 Criteria 的父接口,下面提供了 CriteriaDetachedCriteria

 

     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 (數據庫鎖模式)。


   2)Criterion Projection 進行詳細說明。

 

     Criterion Criteria 的查詢條件。Criteria 提供了 add(Criterion criterion) 方法來添加查詢條件。

     Criterion 接口的主要實現包括:Example ,Junction SimpleExpression

                                  而Junction 的實際使用是它的兩個子類 conjunction disjunction ,分別是使用 AND OR 操作符進行來聯結查詢條件集合。


 

         (1)Criterion 的實例可以通過 Restrictions 工具類來創建,

               Restrictions 提供了大量的靜態方法,如 eq (等於)、 ge (大於等於)、 between 等來方法的創建 Criterion 查詢條件SimpleExpression 實例)。除此之外,

               Restrictions 還提供了方法來創建 conjunction disjunction 實例,通過往該實例的 add(Criteria) 方法來增加查詢條件形成一個查詢條件集合

           Restrictions 子類Expression 。添加了sql(sql[,object[], Type[] ])

 

 

           Example 的創建有所不同, Example 本身提供了一個靜態方法 create(Object entity) ,即根據一個對象(實際使用中一般是映射到數據庫的對象)來創建。然後可以設置一些過濾條件:

                      Example exampleUser =Example.create(u)

                                                 .ignoreCase() // 忽略大小寫

                                                                     .enableLike(MatchMode.ANYWHERE);// String 類型的屬性,無論在那裏值在那裏都匹配。相當於 %value%

     (2)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) 方法加入到查詢條件中去。

 


使用 Criteria 進行查詢,主要要清晰的是 Hibernate 提供了那些類和方法來滿足開發中查詢條件的創建和組裝,下面介紹幾種用法:

 

1. 創建一個Criteria 實例

 

org.hibernate.Criteria接口表示特定持久類的一個查詢。Session Criteria實例的工廠。

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

crit.setMaxResults(50);

List cats = crit.list();

 

 

2. 限制結果集內容

 

一個單獨的查詢條件是org.hibernate.criterion.Criterion 接口的一個實例。

 

org.hibernate.criterion.Restrictions 定義了獲得某些內置Criterion類型的工廠方法。

List cats = sess.createCriteria(Cat.class)

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

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

    .list();

 

約束可以按邏輯分組。

 

List cats = sess.createCriteria(Cat.class)

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

    .add( Restrictions.or(

        Restrictions.eq( "age", new Integer(0) ),

        Restrictions.isNull("age")

    ) )

    .list();

 

List cats = sess.createCriteria(Cat.class)

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

    .add( Restrictions.disjunction()

        .add( Restrictions.isNull("age") )

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

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

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

    ) )

    .list();

 

Hibernate提供了相當多的內置criterion類型(Restrictions 子類), 但是尤其有用的是可以允許你直接使用SQL

 

List cats = sess.createCriteria(Cat.class)

    .add( Restrictions.sql("lower({alias}.name) like lower(?)", "Fritz%",Hibernate.STRING) )

    .list();

 

{alias}佔位符應當被替換爲被查詢實體的列別名。


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

 

 

3. 結果集排序

 

你可以使用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();

 

 

4. 關聯

 

你可以使用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");

}

 

 

5. 動態關聯抓取

 

你可以使用setFetchMode()在運行時定義動態關聯抓取的語義。

 

List cats = sess.createCriteria(Cat.class)

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

    .setFetchMode("mate", FetchMode.EAGER)

    .setFetchMode("kittens", FetchMode.EAGER)

    .list();

 

這個查詢可以通過外連接抓取matekittens

 

 

6. 查詢實例對象

 

org.hibernate.criterion.Example類允許你通過一個給定實例 構建一個條件查詢。

 

Cat cat = new Cat();

cat.setSex('F');

cat.setColor(Color.BLACK);

List results = session.createCriteria(Cat.class)

    .add( Example.create(cat) )

    .list();

 

 

版本屬性、標識符和關聯被忽略。默認情況下值爲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();

 

 

 

7. 投影(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" 。某些投影類型就是被定義爲 分組投影,他們也出現在SQLgroup 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();

 

alias()as()方法簡便的將一個投影實例包裝到另外一個 別名的Projection實例中。簡而言之,

 

當你添加一個投影到一個投影列表中時 你可以爲它指定一個別名:

 

List results = session.createCriteria(Cat.class)

    .setProjection( Projections.projectionList()

        .add( Projections.rowCount(), "catCountByColor" )

        .add( Projections.avg("weight"), "avgWeight" )

        .add( Projections.max("weight"), "maxWeight" )

        .add( Projections.groupProperty("color"), "color" )

    )

    .addOrder( Order.desc("catCountByColor") )

    .addOrder( Order.desc("avgWeight") )

    .list();

 

 

List results = session.createCriteria(Domestic.class, "cat")

    .createAlias("kittens", "kit")

    .setProjection( Projections.projectionList()

        .add( Projections.property("cat.name"), "catName" )

        .add( Projections.property("kit.name"), "kitName" )

    )

    .addOrder( Order.asc("catName") )

    .addOrder( Order.asc("kitName") )

    .list();

 

 

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

 

List results = session.createCriteria(Cat.class)

    .setProjection( Property.forName("name") )

    .add( Property.forName("color").eq(Color.BLACK) )

    .list();


List results = session.createCriteria(Cat.class)

    .setProjection( Projections.projectionList()

        .add( Projections.rowCount().as("catCountByColor") )

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

 

 

 

8. 離線(detached)查詢和子查詢

 

DetachedCriteria類使你在一個session範圍之外創建一個查詢,並且可以使用任意的 Session來執行它。

 

DetachedCriteria query = DetachedCriteria.forClass(Cat.class)

    .add( Property.forName("sex").eq('F') );

//創建一個Session

Session session = .;

Transaction txn = session.beginTransaction();

List results = query.getExecutableCriteria(session).setMaxResults(100).list();

txn.commit();

session.close();

 

 

DetachedCriteria也可以用以表示子查詢。條件實例包含子查詢可以通過 Subqueries或者Property獲得。

 

DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)

    .setProjection( Property.forName("weight").avg() );

session.createCriteria(Cat.class)

    .add( Property.forName("weight).gt(avgWeight) )

    .list();


DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)

    .setProjection( Property.forName("weight") );

session.createCriteria(Cat.class)

    .add( Subqueries.geAll("weight", weights) )

    .list();

 

相互關聯的子查詢也是有可能的:

 

DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")

    .setProjection( Property.forName("weight").avg() )

    .add( Property.forName("cat2.sex").eqProperty("cat.sex") );

session.createCriteria(Cat.class, "cat")

    .add( Property.forName("weight).gt(avgWeightForSex) )

    .list();

 

 

發佈了48 篇原創文章 · 獲贊 7 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章