平时经常用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参数设置。