平時經常用Hibernate,由於習慣表間不建立關聯,所以HQL查詢時候經常要用in語句。
由於表間沒有建立外鍵的關聯關系所以使用in是最常見的代替使用對象po中的set。
但是在寫hql時如果在new object()對象的前面寫上distinct關鍵字是可以去掉重復記錄的,完全不必考慮使用in排除重復記錄,但是在本公司框架中前台的ecside獲得記錄總數時調用的方法中,獲得記錄總數代碼如下:
public Page findBy(String query, PageInfo pageInfo)
{
String countQuery = "select count(*) " + HqlRemoveUtils.removeSelect(query);
return findBy(query, countQuery, pageInfo);
}
public static String removeSelect(String hql)
{
Assert.hasText(hql);
int beginPos = hql.toLowerCase().indexOf("from");
Assert.isTrue(beginPos != -1, " hql : " + hql + " must has a keyword 'from'");
return hql.substring(beginPos);
}
可以看到其獲得記錄總數是從from后面截取hql然后重組hql才獲得記錄總數的,此時在new前面加上distinct關鍵字雖然獲得的記錄是對的,但是在前台的ecside中的記錄總數是錯誤的。
為了避免這種bug不用distinct而使用in關鍵字。這樣就可以不用關聯其他表避免造成多條重復記錄的情況,而是使用子查詢通過where中的條件使用in限制查詢條件,排除重復記錄
使用distinct的代碼如下:
String sql = "select distinct new com.luguang.product.model.LgpProductVo(a.lgpProductId,a.productName,a.productNum,d.userAlias,a.productLeader,a.productGoal,a.description,a.accessControl,'') from LgpProduct as a , LgmUser as d , LgpProjectGroup as e where 1=1 "
+" and a.productLeader=d.userId"
+" and ((a.lgpProductId=e.lgpProductId "
+" and e.userId='"+userId+"'"
+" )or a.accessControl=0)"
+ "/~ and a.productName = '[productName]' ~/"
+ "/~ and a.productNum = '[productNum]' ~/"
+ "/~ and d.userId = '[productLeader]' ~/"
+ "/~ and a.accessControl = '[accessControl]' ~/"
+ "/~ order by [sortingColumn] [sortingDirection] ~/";
使用in的代碼如下:
String sql = "select distinct new com.lg.product.model.LgpProductVo(a.lgpProductId,a.productName,a.productNum,d.userAlias,a.productLeader,a.productGoal,a.description,a.accessControl,'') from LgpProduct as a , LgmUser as d where 1=1 "
+" and a.productLeader=d.userId"
+" and ((a.lgpProductId in (select e.lgpProductId from LgpProjectGroup as e where e.userId='"+userId+"') "
+" )or a.accessControl=0)"
+ "/~ and a.productName = '[productName]' ~/"
+ "/~ and a.productNum = '[productNum]' ~/"
+ "/~ and d.userId = '[productLeader]' ~/"
+ "/~ and a.accessControl = '[accessControl]' ~/"
+ "/~ order by [sortingColumn] [sortingDirection] ~/";
以后處理重復記錄時盡量采用in的形式(針對公司框架目的是避免在ecside中的記錄總數中產生錯誤的記錄統計數量),原始的hibernate框架中使用distinct較為簡單可靠。
我最常用的情況有2種:
1、in后是個子查詢,如 FROM A WHERE A.ID IN (SELECT B.AID FROM B WHERE ...),這樣是沒問題的,如果A.ID 和B.AID是相同的數據類型。
2、in的參數如果已知了,可以直接拼接在后面 如FROM A WHERE A.ID IN (1,2,3,4...)。
3、上面的情況下,通常(1,2,3,4...)都是作為參數傳遞過來的,可能是數組或者List。
假設List<Integer> a;a里面已經有數據了,則HQL查詢條件可以為:
- String hql="FROM A WHERE A.ID IN (:alist)";
- Query query = getSession().createQuery(hql);
- query.setParameterList("alist", a);
String hql="FROM A WHERE A.ID IN (:alist)"; Query query = getSession().createQuery(hql); query.setParameterList("alist", a);
另外,query.setParameterList中的第二個參數,還可以是數組類型,如int[] a,不要被方法名稱迷惑。我也是最近剛學會的這種in參數設置。