【问题标题】:JPA type safe order QueryJPA类型安全订单查询
【发布时间】:2017-06-06 12:27:06
【问题描述】:

我有

实体用户

@NamedQuery(name = "Users.findAll", query = "SELECT u FROM Users u")

像这样使用它:

Query query = em.createNamedQuery("Technologies.findByIsActive", Technologies.class);
query.setFirstResult(technologiesTableModel.getLowItemIndex());
query.setMaxResults(technologiesTableModel.getPageRange().intValue());
List<Technologies> technologies = query.setParameter("isActive", 'Y').getResultList();

但我想对这个结果进行动态排序。我有一个 String 包含我想要排序的列名(字段内容来自请求)。如果不对每个字段和方向进行新查询并键入安全(没有直接附加 order by 子句和字段名称),我该如何做到这一点。

我的研究表明建议使用 CriteriaQuery(我找不到使用上面定义的 NamedQuery 实体的示例)、TypedQuery(我找不到使用排序的示例,只有 setFirstResult setMaxResults。但我需要排序和分页)或 JpaRepository(我找不到具有良好描述的完整实施示例)。

我想要的是按字段名称(我喜欢 String)对数据进行排序,然后对其进行分页(使用 setFirstResultsetMaxResults)。我想用我定义的 NamedQuery 来做到这一点(在实体类声明中)并且 not define query on fly 或附加 order 子句以查询以字符串连接结尾。

编辑:

我所需要的只是一个很好的解释如何实施(以及所有良好的做法)。我不知道该怎么做。我尝试的是:

  • 我的查询在一个地方(大部分)
  • 字符串连接不是创建查询的好习惯。

【问题讨论】:

  • errm,因为 NamedQuery 是静态定义的,所以您静态定义查询字符串(而不是动态)。 Criteria 或 JPQL 都支持您在运行时定义查询。任何 JPA 文档都会证明这一点。 datanucleus.org/products/accessplatform_5_1/jpa/…
  • 命名查询不是动态的。看看这个话题stackoverflow.com/questions/22167730/…我会选择标准或sql。由于 JPA 标准 API 不是最好的,QueryDSL 可能是一个选项或 Hibernate API 本身。
  • 如果不使用该 JPA 提供程序,您将不会使用 Hibernate API,或者您想要可移植性(即理智)
  • 好的,NamedQuery 是静态定义的!我明白了!但是要求像我的分页(使用方法 setFirstResultsetMaxResults)这样的解决方案,他们不使用 rownumcase 的复杂查询 子句。

标签: java jpa


【解决方案1】:

我用 case 子句解决了我的问题。在我的实体中,我添加了 orderClause 字段,例如:

public static final String orderClause = " order by "
            + "case when :orderField = 'id' and :orderDirection = 'asc' then s.id else 0 end ASC, "
            + "case when :orderField = 'id' and :orderDirection = 'desc' then s.id else 0 end DESC, "
            + "case when :orderField = 'username' and :orderDirection = 'asc' then s.username else '' end ASC, "
            + "case when :orderField = 'username' and :orderDirection = 'desc' then s.username else '' end DESC, "
            + "s.id ASC";

并将此字段添加到需要的命名查询的末尾,例如:

@NamedQueries(
{
    @NamedQuery(name = "SysRoles.findAll", query = "SELECT s FROM SysRoles s" + SysRoles.orderClause),
    @NamedQuery(name = "SysRoles.findByIsActive", query = "SELECT s FROM SysRoles s WHERE s.isActive = :isActive " + SysRoles.orderClause)
}) 
public class SysRoles implements Serializable {
    public static final String orderClause = " order by "
        + "case when :orderField = 'id' and :orderDirection = 'asc' then s.id else 0 end ASC, "
        + "case when :orderField = 'id' and :orderDirection = 'desc' then s.id else 0 end DESC, "
        + "case when :orderField = 'username' and :orderDirection = 'asc' then s.username else '' end ASC, "
        + "case when :orderField = 'username' and :orderDirection = 'desc' then s.username else '' end DESC, "
        + "case when :orderField = 'isActive' and :orderDirection = 'asc' then s.isActive else '' end ASC, "
        + "case when :orderField = 'isActive' and :orderDirection = 'desc' then s.isActive else '' end DESC, "
        + "s.id ASC";
 ...
}

我将我的命名查询称为:

Query query = em.createNamedQuery("SysRoles .findAll", SysRoles.class);
        //Pagination
        query.setFirstResult(lowItemIndex);
        query.setMaxResults(maxResults);
List<SysRoles> sysUsers= query.setParameter("isActive", "Y")
                 //ditection of sorting
                .setParameter("orderDirection", direction)
                 //name of sorting columns
                .setParameter("orderField", orderByColumnName).getResultList();

有关按列名排序和良好解释的更多信息,请参阅博客 asktom.oracle.com 中的 here

使用这个解决方案,我们有一些难看的查询,但它们在一个地方,并且排序也在那里。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-15
    相关资源
    最近更新 更多