好的,我有以下(缩写)3实体和HibernateUtil类。
public class Tag {
@Id
BigDecimal id;
String tag
@ManyToMany( mappedBy="tags" )
List<Label> labels;
}
public class Label {
@Id
BigDecimal id;
String label;
@ManyToMany( targetEntity=Tag.class )
List<Tag> tags;
}
public class Data {
@Id
BigDecimal id;
BigDecimal data;
@ManyToOne
Label label;
}
public class HibernateUtil {
public static List pagedQuery(DetachedCriteria detachedCriteria, Integer start, Integer size) throws WebApplicationException {
Session session = getSession();
try {
Transaction transaction = session.beginTransaction();
List records = detachedCriteria.getExecutableCriteria(session)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.setFirstResult(start)
.setMaxResults(size)
.list();
transaction.commit();
return records;
} catch (Exception e) {
// Place Logger here...
throw new WebApplicationException(e);
} finally {
session.close();
}
}
}
我遇到的问题是,当我尝试使用HibernateUtil.pagedQuery(detatchedCriteria,start,size)查询Data类时,我的结果列表与size参数不匹配。我发现其原因是hibernate构建查询以包含标记(Data.Label.Tags)的方式。
例如,当Label有多个关联的Tags时,完整的分页查询中使用的Data对象子查询的结果列表将如下所示(我通过解析sql Hibernate吐出到控制台找到了这个)< / p>
如果我用size = 3调用它,那么返回的结果集将是
然而,Hibernate会将前两行组合在一起(因为它们是相同的Data对象),而我返回的List对象的大小为2(Data-1&amp; Data-2)
我尝试使用我通过Google找到的Projection方法替换setResultTransformer方法,但之后只返回了Data对象的id。
有人对我有任何建议吗?我不知道从哪里开始......
答案 0 :(得分:2)
你正面临着一个用hibernate分页的常见问题。 resultTransformer应用于“Java”端,因此已经在DB端进行了分页。
最简单的(可能不是最优化的)是做两个查询,一个是投影和分页(就像你已经做过的那个),另一个是使用投影id。这是一个例子:
//get the projection
Criteria criteria = factory.getCurrentSession().createCriteria(getEntityClass());
criteria.setProjection(Projections.distinct((Projections.projectionList().add(Projections.id()).add(Projections.property("name")))));
//paginate the results
criteria.setMaxResults(pageSize);
criteria.setFirstResult(first);
List<Object[]> idList = criteria.list();
//get the id's from the projection
List<Long> longList = new ArrayList<Long>();
for (Object[] long1 : idList) {
Object[] record = long1;
longList.add((Long) record[0]);
}
if (longList.size() > 0) {
//get all the id's corresponding to the projection,
//then apply distinct root entity
criteria = factory.getCurrentSession().createCriteria(getEntityClass());
criteria.add(Restrictions.in("id", longList));
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
} else {
//no results, so let's ommit the second query to the DB
return new ArrayList<E>();
}
return criteria.list();