java - 如何在 Hibernate 中使用具有 ManyToMany 关联的嵌套对象正确分页?

标签 java hibernate jersey jax-rs

好的,所以我有以下(缩写)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) 的方式。

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

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

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

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

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

我尝试用通过 Google 找到的投影方法替换 setResultTransformer 方法,但只返回数据对象的 ID。

有人可以给我一些建议吗?我不知道从这里去哪里......

最佳答案

您遇到了使用 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();

关于java - 如何在 Hibernate 中使用具有 ManyToMany 关联的嵌套对象正确分页?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13338813/

相关文章:

java - 使用名称方法查找类型异常

java - boolean allLess(int[]一,int[]二)方法

java - 获取 org.hibernate.HibernateException : No CurrentSessionContext configured

java - Jersey REST 服务的响应不包含空字段

java - com.sun.jersey.spi.container.ContainerResponse : A message body writer for Java class

java - Jersey 将空列表和单元素列表序列化为数组

java - 如何在 Java 中为 Jersey 框架的 SOAP Web 请求生成 bean 类

java - 单元测试 AEM 6.1 和模拟 sling、Jcr 和 Osgi

java - 具有一对多关联的 Hibernate 条件

java - 找不到具有多个上下文的属性 :property-placeholder