JPA类型安全订单查询

时间:2017-06-06 12:27:07

标签: java jpa

我有

实体用户

@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 ,其中包含我要排序的列名(字段内容来自请求)。如果没有针对每个字段和方向的新查询并且键入safe(如果没有带字段名称的直接附加order by子句),我该怎么做呢。

我的研究显示使用CriteriaQuery的建议(我找不到使用上面定义的 NamedQuery 实例),TypedQuery(我找不到订购示例,只能使用 setFirstResult setMaxResults 。但我需要排序和分页)或JpaRepository(我找不到完整的实现示例和良好的描述)。

我想要的是按字段名称(我喜欢String)对数据进行排序,然后对其进行分页(使用 setFirstResult setMaxResults )。我希望使用我定义的 NamedQuery (在实体类声明中)和不在运行时定义查询或附加order子句来查询以字符串连接结束。

修改

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

  • 我的询问是在一个地方(大多数)
  • 字符串连接不是创建查询的好方法。

1 个答案:

答案 0 :(得分:0)

我使用 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

使用这个解决方案我们有一些丑陋的查询,但它们在一个地方,订购也在那里。