0

好的,所以我有以下(缩写)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 参数不匹配。我发现原因是休眠构建查询以包含标签(Data.Label.Tags)的方式。

例如,当标签具有多个关联标签时,完整分页查询中使用的数据对象子查询的结果列表如下所示(我通过解析 Hibernate 向控制台吐出的 sql 发现了这一点)

  1. 数据 1;标签:标签 1
  2. 数据 1;标签;标签 2
  3. 数据 2;标签;标签 1
  4. 数据 2;标签;标签 2
  5. ETC...

如果我用 size=3 调用它,那么返回的结果集将是

  1. 数据 1;标签:标签 1
  2. 数据 1;标签;标签 2
  3. 数据 2;标签;标签 1

但是,Hibernate 会将前两行组合在一起(因为它们是相同的 Data 对象),并且我返回的 List 对象的大小为 2(Data-1 & Data-2)

我试图用我通过 Google 找到的 Projection 方法替换 setResultTransformer 方法,但它只返回了 Data 对象的 id。

有人对我有什么建议吗?我不知道从这里去哪里......

4

1 回答 1

2

您面临一个常见的问题,即使用休眠进行分页。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();
于 2012-11-12T12:30:48.557 回答