postgresql - JPQL EclipseLink 分页

标签 postgresql jakarta-ee pagination eclipselink jpql

我在使用 EclipseLink 的 JavaEE Web 应用程序中实现分页时遇到问题。

目标实体:

@Entity
@JsonIdentityInfo(generator=JSOGGenerator.class)
@NamedQueries({
    @NamedQuery(
        name = Project.QUERY_FIND_FOR_ADMIN,
        query = "SELECT DISTINCT p " +
                "FROM Project p " +
                "LEFT JOIN FETCH p.documents " +
                "LEFT JOIN FETCH p.projectManager " +
                "LEFT JOIN FETCH p.watchingUsers " +
                "LEFT JOIN FETCH p.users " +
                "LEFT JOIN FETCH p.scheme " +
                "ORDER BY p.id",
        hints = {
            @QueryHint(name = QueryHints.LEFT_FETCH, value = "p.documents.states")
//            ,@QueryHint(name = QueryHints.JDBC_FETCH_SIZE, value = Project.ITEMS_PER_PAGE) // does not change anything
//            ,@QueryHint(name = QueryHints.JDBC_MAX_ROWS, value = Project.ITEMS_PER_PAGE) // results in a LIMIT statement
        }
    )
})
public class Project extends BaseEntity {

    public static final String ITEMS_PER_PAGE = "" + 2;

    ...
}

一个BaseDAO

public abstract class BaseEntityDAO<Entity> extends AbstractDAO {

  ...

    protected List<Entity> executeQuery(String queryName, Map<String, ?> parameters, final int firstResult) {
        TypedQuery<Entity> query = prepareQuery(queryName, parameters);
        query.setFirstResult(firstResult);
        query.setMaxResults(Integer.parseInt(Project.ITEMS_PER_PAGE));
        return query.getResultList();
    }

}

这会导致以下查询:

// Logging
[2016-09-11T13:16:26.141+0200] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=28 _ThreadName=Thread-8] [timeMillis: 1473592586141] [levelValue: 800] [[
  page: 1]]
// Logging
[2016-09-11T13:16:26.141+0200] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=28 _ThreadName=Thread-8] [timeMillis: 1473592586141] [levelValue: 800] [[
  first row: 0]]

[2016-09-11T13:16:26.143+0200] [glassfish 4.1] [FINE] [] [org.eclipse.persistence.session./file:/Users/timtoheus/NetBeansProjects/discanno/target/swan-2.0/WEB-INF/classes/_SwanPU.sql] [tid: _ThreadID=32 _ThreadName=http-listener-1(5)] [timeMillis: 1473592586143] [levelValue: 500] [[
  SELECT DISTINCT t1.ID, t1.Name, t1.CREATOR_ID, t1.COLORSCHEME_ID, t0.ID, t0.Name, t0.TOKENIZATIONLANG, t0.Scheme FROM SCHEME t1 LEFT OUTER JOIN PROJECT t0 ON (t0.Scheme = t1.ID)]]

[2016-09-11T13:16:26.144+0200] [glassfish 4.1] [FINE] [] [org.eclipse.persistence.session./file:/Users/timtoheus/NetBeansProjects/discanno/target/swan-2.0/WEB-INF/classes/_SwanPU.sql] [tid: _ThreadID=28 _ThreadName=http-listener-1(1)] [timeMillis: 1473592586144] [levelValue: 500] [[
  SELECT DISTINCT t1.ID AS a1, t1.Name AS a2, t1.TOKENIZATIONLANG AS a3, t1.Scheme AS a4, t0.ID AS a5, t0.Name AS a6, t0.Text AS a7, 
  t0.project_fk AS a8, t2.ID AS a9, t2.Completed AS a10, t2.LastEdit AS a11, t2.document_fk AS a12, t2.user_fk AS a13, 
  t3.ID AS a14, t3.CreateDate AS a15, t3.EMail AS a16, t3.Lastname AS a17, t3.Password AS a18, t3.Prename AS a19, t3.Role AS a20, 
  t3.session AS a21, t4.ID AS a22, t4.CreateDate AS a23, t4.EMail AS a24, t4.Lastname AS a25, t4.Password AS a26, t4.Prename AS a27, 
  t4.Role AS a28, t4.session AS a29, t5.ID AS a30, t5.CreateDate AS a31, t5.EMail AS a32, t5.Lastname AS a33, t5.Password AS a34, 
  t5.Prename AS a35, t5.Role AS a36, t5.session AS a37, t6.ID AS a38, t6.Name AS a39, t6.CREATOR_ID AS a40, t6.COLORSCHEME_ID AS a41 F
  ROM PROJECT t1 LEFT OUTER JOIN DOCUMENT t0 ON (t0.project_fk = t1.ID) 
  LEFT OUTER JOIN STATE t2 ON (t2.document_fk = t0.ID) 
  LEFT OUTER JOIN (PROJECTS_MANAGER t7 JOIN Users t3 ON (t3.ID = t7.MANAGER_ID)) ON (t7.PROJECT_ID = t1.ID) 
  LEFT OUTER JOIN (PROJECTS_WATCHINGUSERS t8 JOIN Users t4 ON (t4.ID = t8.WATCHINGUSER_ID)) ON (t8.PROJECT_ID = t1.ID) 
  LEFT OUTER JOIN (USERS_PROJECTS t9 JOIN Users t5 ON (t5.ID = t9.USERS_ID)) ON (t9.PROJECT_ID = t1.ID) 
  LEFT OUTER JOIN SCHEME t6 ON (t6.ID = t1.Scheme) 
  ORDER BY t1.ID 
  LIMIT ? OFFSET ?
    bind => [2, 0]]]
// Logging
[2016-09-11T13:16:28.885+0200] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=28 _ThreadName=Thread-8] [timeMillis: 1473592588885] [levelValue: 800] [[
  number of results: 1]]

如您所见,查询使用了 LIMIT 和 OFFSET 并正确绑定(bind)了所需的参数,但无论 page/OFFSET 参数是什么,它总是返回相同的结果。它总是返回 'Project1' 但数据库中总共有 6 个项目(pgAdmin 和 IntelliJ 可以证明这一点)。此外,将 ORDER BY 更改为 name/id 或增加“Project.ITEMS_PER_PAGE”不会改变任何内容。所需的行为应该返回声明为“Project.ITEMS_PER_PAGE”的行数,而不是总是一个。我想避免编写原生 SQL 查询。

如此处所列,EclipseLink 应支持 PostgreSQL: https://www.eclipse.org/eclipselink/documentation/2.6/concepts/app_tl_ext001.htm

JPQL 不支持表达式“LIMIT”、“FETCH FIRST ROWS”和“OFFSET”。如上所述,我还尝试了一些 QueryHints。奇怪的是,如果我在 Postgres 中手动执行查询,它会正确返回所需数量的结果。

我希望有人能给我提示。

环境:GlassFish 4.1、PostgreSQL ~9.3、EclipseLink 2.6.2

最佳答案

尝试删除左外连接 - 它们实际上不适用于分页,因为分页选项在行级别,而多对多关系上的外连接会增加完全读取实体所需的行数。这可能会导致您的实体跨越多行,因此即使您要求下一个“实体”,您也只会得到下一行……这恰好是针对同一个第一个实体。

尝试在使用分页时对 ManyToMany 和 OneToMany 关系使用批读取,使用 query hintannotation在映射上

关于postgresql - JPQL EclipseLink 分页,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39435633/

相关文章:

PHP 数组分页

postgresql - 为什么在使用 pg-promise 的事务中无法解锁咨询锁?

ruby-on-rails - Rails 建模比赛,postgres 数组的好时机?

Java InetAddress 到 PostgreSQL inet,反之亦然

jakarta-ee - javax.el.E​​LException : The identifier [return] is not a valid Java identifier

java - spring web mvc中的组合框

postgresql - Citrus:一个 2 节点的 POSTGRESQL 集群是否可行?如果可行,如何实现?

java - Hibernate 模板中的泛型问题

checkbox - 剑道网格 : Column Header Checkbox 'Check All' that checks boxes across grid all pages

html - 我怎样才能通过 AngularJS 进行分页?