廢話不多說,今天主要想記錄的是 DetachedCriteria的應用。相信許多人在使用Hibernate時,都會比較習慣使用HQL來對資料庫下查詢指令,因為它跟Sql Query非常相似,基本上會Sql Query,幾乎就會使用HQL。但問題是code不總是自己寫,還要維護前人或其他人的code,也因此總還是會有機會去碰觸使用Criteria寫的資料庫查詢程式,所以索性還是耐著性子,上網爬了點文,將自己試跑過的DetachedCriteria的一些相關功能做個整理與紀錄。
在接下來的介紹中,打算以 DetachedCrititeria的實例程式對照轉譯成SQL後的樣子來進行解說,對我個人來說,這樣是學最快也是最好記憶的方式,若想知道一些個別介面的詳細使用說明,網路上有許多文可以爬,例如這篇有很詳細的DetachedCriteria的完整說明或是去查詢Hibernate API。
第一個detachedCriteria實例:
Property versionNumberPro=Property.forName("versionNumber"); Property apIdPro=Property.forName("apId"); DetachedCriteria mainQuery= DetachedCriteria.forClass(AgentAp.class) .addOrder(Order.desc("apId")); DetachedCriteria subQuery=DetachedCriteria.forClass(AgentAp.class); subQuery.setProjection(Property.forName("apId")) .add(Restrictions.disjunction().add(versionNumberPro.eq(new String("1.0.1"))) .add(versionNumberPro.eq(new String("1.0.2")))) .add(Restrictions.conjunction().add(apIdPro.ge(new Integer(114))) .add(apIdPro.le(new Integer(128)))); ListHibernate 翻譯出來的 sql長的樣子如下:因此我們可以從下面sql開始對照DetachedCriteria指令。listAps= mainQuery.add(Property.forName("apId").in(subQuery)) .getExecutableCriteria(this.getSession()).list();//
select this_.AP_ID as AP1_84_0_, this_.IS_UPDATE as IS2_84_0_, this_.VERSION_DATE as VERSION3_84_0_, this_.VERSION_NUMBER as VERSION4_84_0_ from AGENT_AP this_ where this_.AP_ID in ( select max(this_.AP_ID) as y0_ from AGENT_AP this_ where ( this_.VERSION_NUMBER=? or this_.VERSION_NUMBER=? ) and ( this_.AP_ID>=? and this_.AP_ID<=? ) ) order by this_.AP_ID desc首先 DetachedCriteria mainQuery= DetachedCriteria.forClass(AgentAp.class) ,
就是sql中的
select this_.AP_ID as AP1_84_0_, this_.IS_UPDATE as IS2_84_0_, this_.VERSION_DATE as VERSION3_84_0_, this_.VERSION_NUMBER as VERSION4_84_0_ from AGENT_AP this_
接下來,由於我的這個主查詢需要根據子查詢的結果當作主查詢的條件,因此在Criteria程式中,我會建立一個相當於子查詢功能(在sql中)的subQuery(一樣是DetachedCriteria類別): DetachedCriteria subQuery=DetachedCriteria.forClass(AgentAp.class);
建立好子查詢的DetachedCriteria後,接下來我們要考慮的是,主查詢是要以這個子查詢的哪個欄位來當作條件依據,在本例子中,是要以"apId"這個entity的property(與實際在db中的field name不一定相等,看各位自己名字的取法),因此會有這句的設定: subQuery.setProjection(Property.forName("apId").max()) 剛開始看這些東西,真的會覺得很不習慣,為什麼要這樣取,不過其實也沒太多為什麼,寫多看久,自然就知道要這樣用,而透過subQuery.setProjection(Property.forName("apId")設定好要select出來的欄位後,大家有注意到後面還有個max()方法,它其實就是取前面那個欄位名稱的最大值,到目前為止,所看到的Criteria程式,剛好就可以翻譯成
select max(this_.AP_ID) as y0_ from AGENT_AP this_ 這樣的一段sql。
在這段子查詢中,我們也必須根據一些條件去過濾它,因此會有後面這段
.add(Restrictions.disjunction().add(versionNumberPro.eq(new String("1.0.1"))) .add(versionNumberPro.eq(new String("1.0.2")))) .add(Restrictions.conjunction().add(apIdPro.ge(new Integer(114))).add(apIdPro.le(new Integer(128))));看起來好像有點小複雜,其實轉成sql就是下面這段:
where ( this_.VERSION_NUMBER=?
or
this_.VERSION_NUMBER=? )
and ( this_.AP_ID>=?
and
this_.AP_ID<=? )
其中,Restrictions.disjunction()就是指我們接下來add的條件都是or起來的,如上面對VERSION_NUMBER 條件的or操作,
而Restrictions.conjunction()就是指接下來的條件都是and起來的,如上面對AP_ID的操作。
到現在為止,子查詢的部分已經解釋完畢,接下來就是將主查詢與子查詢給串起來,相信看到這邊在回顧一下最上面的Criteria程式,也能猜到是這句
mainQuery.add(Property.forName("apId").in(subQuery)
其實這部分還算滿直覺的,就是將主查詢加入一個子查詢,其中查詢的依據就是依據"apId"這個欄位,產生的sql如下這,紅色標記的部分當然就是子查詢了。
where this_.AP_ID in ( select max(this_.AP_ID) as y0_
from AGENT_AP this_
where ( this_.VERSION_NUMBER=?
or this_.VERSION_NUMBER=? )
and ( this_.AP_ID>=?
and this_.AP_ID<=? )
)
order by this_.AP_ID desc
奇怪,這個 order by 是怎麼來的,好像漏說了,恩對,確實沒說,這個order by 是一開始在建立主要的mainQuery時就指定,
DetachedCriteria mainQuery= DetachedCriteria.forClass(AgentAp.class) .addOrder(Order.desc("apId"))。
至此透過一個簡單的DetachedCriteria範例程式與SQL Query的對照,大致可以掌握了解DetachedCriteria的基本常用的一些方法,當然其實還有非常多的東西沒有講到,希望能在近期陸續將更多實用的相關方法補齊。