現(xiàn)在對 Hibernate的Criteria 的用法進(jìn)行總結(jié):
Hibernate 設(shè)計了 CriteriaSpecification 作為 Criteria 的父接口咏花,下面提供了 Criteria和DetachedCriteria 。Criteria 和 DetachedCriteria 的主要區(qū)別在于創(chuàng)建的形式不一樣棕硫, Criteria 是在線的洲敢,所以它是由 Hibernate Session 進(jìn)行創(chuàng)建的沉桌;而 DetachedCriteria 是離線的坦冠,創(chuàng)建時無需Session领迈,DetachedCriteria 提供了 2 個靜態(tài)方法 forClass(Class) 或 forEntityName(Name)進(jìn)行DetachedCriteria 實(shí)例的創(chuàng)建彻磁。 Spring 的框架提供了
getHibernateTemplate().findByCriteria(detachedCriteria)方法可以很方便地根據(jù)DetachedCriteria 來返回查詢結(jié)果。
Criteria 和 DetachedCriteria 均可使用 Criterion 和 Projection 設(shè)置查詢條件狸捅≈则眩可以設(shè)置 FetchMode( 聯(lián)合查詢抓取的模式 ) ,設(shè)置排序方式尘喝。對于 Criteria 還可以設(shè)置 FlushModel(沖刷 Session 的方式)和 LockMode (數(shù)據(jù)庫鎖模式)磁浇。
下面對 Criterion 和 Projection 進(jìn)行詳細(xì)說明。
Criterion 是 Criteria 的查詢條件朽褪。Criteria 提供了 add(Criterion criterion) 方法來添加查詢條件置吓。
Criterion 接口的主要實(shí)現(xiàn)包括: Example 无虚、 Junction 和 SimpleExpression 。而Junction 的實(shí)際使用是它的兩個子類 conjunction 和 disjunction 衍锚,分別是使用 AND 和 OR 操作符進(jìn)行來聯(lián)結(jié)查詢條件集合友题。
Criterion 的實(shí)例可以通過 Restrictions 工具類來創(chuàng)建,Restrictions 提供了大量的靜態(tài)方法构拳,如 eq (等于)咆爽、 ge (大于等于)、 between 等來方法的創(chuàng)建 Criterion 查詢條件(SimpleExpression 實(shí)例)置森。除此之外斗埂, Restrictions 還提供了方法來創(chuàng)建 conjunction 和disjunction 實(shí)例,通過往該實(shí)例的 add(Criteria) 方法來增加查詢條件形成一個查詢條件集合凫海。
至于 Example 的創(chuàng)建有所不同呛凶, Example 本身提供了一個靜態(tài)方法 create(Object?entity) ,即根據(jù)一個對象(實(shí)際使用中一般是映射到數(shù)據(jù)庫的對象)來創(chuàng)建行贪。然后可以設(shè)置一些過濾條件:
Example?exampleUser?=Example.create(u)//?忽略大小寫.ignoreCase()//?對?String?類型的屬性漾稀,無論在那里值在那里都匹配。相當(dāng)于?%value%.enableLike(MatchMode.ANYWHERE);
Project 主要是讓 Criteria 能夠進(jìn)行報表查詢建瘫,并可以實(shí)現(xiàn)分組崭捍。 Project 主要有SimpleProjection 、 ProjectionList 和 Property 三個實(shí)現(xiàn)啰脚。其中 SimpleProjection 和ProjectionList 的實(shí)例化是由內(nèi)建的 Projections 來完成殷蛇,如提供的 avg 、 count 橄浓、 max 粒梦、min 、 sum 可以讓開發(fā)者很容易對某個字段進(jìn)行統(tǒng)計查詢荸实。
Property 是對某個字段進(jìn)行查詢條件的設(shè)置匀们,如通過
Porperty.forName(“color”).in(new String[]{“black”,”red”,”write”}); 則可以創(chuàng)建一個 Project 實(shí)例。通criteria 的 add(Project) 方法加入到查詢條件中去准给。
使用 Criteria 進(jìn)行查詢泄朴,主要要清晰的是 Hibernate 提供了那些類和方法來滿足開發(fā)中查詢條件的創(chuàng)建和組裝,下面介紹幾種用法:
1. 創(chuàng)建一個Criteria 實(shí)例
org.hibernate.Criteria接口表示特定持久類的一個查詢露氮。Session是 Criteria實(shí)例的工廠叼旋。
Criteria?crit?=?sess.createCriteria(Cat.class);crit.setMaxResults(50);List?cats?=?crit.list();
2. 限制結(jié)果集內(nèi)容
一個單獨(dú)的查詢條件是org.hibernate.criterion.Criterion 接口的一個實(shí)例。
org.hibernate.criterion.Restrictions類 定義了獲得某些內(nèi)置Criterion類型的工廠方法沦辙。
List?cats?=?sess.createCriteria(Cat.class)?.add(?Restrictions.like("name","Fritz%")?)?.add(?Restrictions.between("weight",?minWeight,?maxWeight)?).list();
約束可以按邏輯分組夫植。
Listcats?=?sess.createCriteria(Cat.class)?.add(?Restrictions.like("name","Fritz%")?)?.add(?Restrictions.or(?????Restrictions.eq("age",newInteger(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提供了相當(dāng)多的內(nèi)置criterion類型(Restrictions 子類), 但是尤其有用的是可以允許你直接使用SQL。
List?cats?=?sess.createCriteria(Cat.class).add(?Restrictions.sql("lower({alias}.name)?like?lower(?)","Fritz%",Hibernate.STRING)?)?.list();
{alias}占位符應(yīng)當(dāng)被替換為被查詢實(shí)體的列別名。
Property實(shí)例是獲得一個條件的另外一種途徑详民。你可以通過調(diào)用Property.forName() 創(chuàng)建一個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. 結(jié)果集排序
你可以使用org.hibernate.criterion.Order來為查詢結(jié)果排序。
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. 關(guān)聯(lián)
你可以使用createCriteria()非常容易的在互相關(guān)聯(lián)的實(shí)體間建立 約束沈跨。
List?cats?=?sess.createCriteria(Cat.class).add(?Restrictions.like("name","F%").createCriteria("kittens").add(?Restrictions.like("name","F%").list();
注意第二個 createCriteria()返回一個新的 Criteria實(shí)例由捎,該實(shí)例引用kittens 集合中的元素。
接下來饿凛,替換形態(tài)在某些情況下也是很有用的狞玛。
List?cats?=?sess.createCriteria(Cat.class)????.createAlias("kittens","kt")????.createAlias("mate","mt")????.add(?Restrictions.eqProperty("kt.name","mt.name")?)????.list();
(createAlias()并不創(chuàng)建一個新的 Criteria實(shí)例。)
Cat實(shí)例所保存的之前兩次查詢所返回的kittens集合是 沒有被條件預(yù)過濾的涧窒。如果你希望只獲得
符合條件的kittens心肪, 你必須使用returnMaps()。
Listcats?=?sess.createCriteria(Cat.class)????.createCriteria("kittens","kt")????.add(Restrictions.eq("name","F%")?)????.returnMaps()????.list();Iteratoriter?=?cats.iterator();while(?iter.hasNext()?)?{Mapmap=?(Map)?iter.next();Catcat?=?(Cat)map.get(Criteria.ROOT_ALIAS);Catkitten?=?(Cat)map.get("kt");}
5. 動態(tài)關(guān)聯(lián)抓取
你可以使用setFetchMode()在運(yùn)行時定義動態(tài)關(guān)聯(lián)抓取的語義纠吴。
List?cats?=?sess.createCriteria(Cat.class)????.add(?Restrictions.like("name","Fritz%")?)????.setFetchMode("mate",?FetchMode.EAGER)????.setFetchMode("kittens",?FetchMode.EAGER)????.list();
這個查詢可以通過外連接抓取mate和kittens硬鞍。
6. 查詢示例
org.hibernate.criterion.Example類允許你通過一個給定實(shí)例 構(gòu)建一個條件查詢。
Cat?cat?=newCat();cat.setSex('F');cat.setColor(Color.BLACK);List?results?=?session.createCriteria(Cat.class).add(?Example.create(cat)?).list();
版本屬性戴已、標(biāo)識符和關(guān)聯(lián)被忽略固该。默認(rèn)情況下值為null的屬性將被排除。
可以自行調(diào)整Example使之更實(shí)用糖儡。
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?comparisonsList?results?=?session.createCriteria(Cat.class)????.add(example).list();
甚至可以使用examples在關(guān)聯(lián)對象上放置條件伐坏。
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 的實(shí)例工廠握联。我們通過調(diào)用setProjection()應(yīng)用投影到一個查詢桦沉。
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" 。某些投影類型就是被定義為 分組投影拴疤,他們也出現(xiàn)在SQL的group by子句中。
可以選擇把一個別名指派給一個投影独泞,這樣可以使投影值被約束或排序所引用呐矾。下面是兩種不同的實(shí)現(xiàn)方式:
List?results?=?session.createCriteria(Cat.class)????.setProjection(?Projections.alias(?Projections.groupProperty("color"),"colr")?)????.addOrder(?Order.asc("colr")?).list();
Listresults?=?session.createCriteria(Cat.class)????.setProjection(?Projections.groupProperty("color").as("colr")?)????.addOrder(?Order.asc("colr")?).list();
alias()和as()方法簡便的將一個投影實(shí)例包裝到另外一個 別名的Projection實(shí)例中。簡而言之懦砂,
當(dāng)你添加一個投影到一個投影列表中時 你可以為它指定一個別名:
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();
Listresults?=?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范圍之外創(chuàng)建一個查詢蜒犯,并且可以使用任意的?Session來執(zhí)行它。DetachedCriteria?query?=?DetachedCriteria.forClass(Cat.class)????.add(?Property.forName("sex").eq('F'));//創(chuàng)建一個SessionSession?session?=?Transaction?txn?=?session.beginTransaction();List?results?=?query.getExecutableCriteria(session).setMaxResults(100).list();txn.commit();session.close();
DetachedCriteria也可以用以表示子查詢荞膘。條件實(shí)例包含子查詢可以通過 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();
相互關(guān)聯(lián)的子查詢也是有可能的:
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();