解决Hibernate Criteria查询中distinct root entity的问题

举个例子说明这个问题:有一种Entity叫article,另外一种Entity叫tag,一个article可以关联多个tag。在查询article的时候,我们可以使用tag作为查询条件。

 

比如有一个article "ABC" 关联"tagA"和"tagB"。我们在查询的时候,同时把"tagA"和"tagB"作为查询条件,想要查询出所有标示为"tagA"或者"tagB"的article。这种情况下,使用Hibernate criteria查询时会将article "ABC"作为查询结果返回两次。这是由SQL的join决定的。如果用户要求这种情况下只返回一条记录该怎么做呢?

 

看了Hibernate的javadoc之后我本来以为“criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)”方法可以解决这个问题,但是经过尝试不行。而且即使可以,据我所知(如果不对请指正),ResultTransformer也只是对查询结果集做手脚,这样会造成分页的问题(本来一页应该有10条记录,但如果仅仅是在查询当前页做distinct,会导致本页只有9条)。所以不得不找其他方法。

 

给我帮助的是来自以下链接的文章:

 

http://floledermann.blogspot.com/2007/10/solving-hibernate-criterias-distinct.html

 

该文章解决的方法基于以下思路:

 

1. 使用criteria查询的时候不查询整个记录,只查询"distinct(root_entity_id_field)",这样就可以保证查询的结果是唯一的;

2. 再使用一个条件为in (id_lists got from the above query)的查询、并包含该entity的所有字段的语句进行查询,得到的结果就是想要的结果。

 

代码(from http://floledermann.blogspot.com/2007/10/solving-hibernate-criterias-distinct.html ):

 

  if (queryDate != null) {
  // project result to distinct ids,
  // including columns used for sorting
  criteria.setProjection(Projections.distinct(
    Projections.projectionList()
      .add(Projections.id())
      .add(Projections.property("birthDate"))
  ));
  List list = criteria.list();

  // unfortunately we have to copy the ids out of the
  // resulting Object[] List
  List idlist = new ArrayList<long>();

  for (Iterator iditer = list.iterator(); iditer.hasNext();) {
    Object[] record = (Object[]) iditer.next();
    idlist.add((Long)record[0]);
  }

  // another Hibernate stupidity: empty Lists cause
  // Expression.in to throw an error
  if (idlist.size() > 0) {
    criteria = getSession().createCriteria(Cat.class);
    criteria.add(Expression.in("id", idlist));
  }
  else {
    return new ArrayList();
  }
}
 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值