你可以将LIMIT放在JPQL子查询中吗?

huangapple go评论65阅读模式
英文:

How can you put your LIMIT inside a subquery in JPQL?

问题

// 假设您有一个名为 'entityManager' 的 EntityManager

int limit = 3;
int offset = 3;
String jpql = "SELECT u FROM User u ORDER BY u.id";

TypedQuery<User> query = entityManager.createQuery(jpql, User.class);
query.setMaxResults(limit);
query.setFirstResult(offset);

List<User> users = query.getResultList();

// 如果您想要颠倒返回列表的顺序
Collections.reverse(users);
英文:

Are queries like this

SELECT *
FROM  (
   SELECT *
   FROM   users
   ORDER  BY id
   LIMIT  3
   OFFSET 3
   ) sub
ORDER  BY id DESC;

translatable into JPQL? I'm not sure since LIMIT and OFFSET, which are not supported directly inside a JPQL string, are placed inside a subquery. The problem with setMaxResults() and setFirstResult() is that the associated SQL keywords are going to be appended to the outermost query whatever you do, it is not customizable

My LIMIT, OFFSET and GROUP BY values are actually dynamic and represent pagination parameters passed in an HTTP request. I know OFFSET is not very good for pagination, but even if you replace it with WHERE, you're still left with LIMIT that should still be inside a subquery

How do I turn that SQL into JPQL?

P.S.: In case you're wondering why I need LIMIT and OFFSET inside a subquery, you may visit this page

UPD: Here's ChatGPT-4's suggestion

// Assuming you have an EntityManager named &#39;entityManager&#39;

int limit = 3;
int offset = 3;
String jpql = &quot;SELECT u FROM User u ORDER BY u.id&quot;;

TypedQuery&lt;User&gt; query = entityManager.createQuery(jpql, User.class);
query.setMaxResults(limit);
query.setFirstResult(offset);

List&lt;User&gt; users = query.getResultList();

// If you want to reverse the order of the returned list
Collections.reverse(users);

答案1

得分: 1

我认为你上面提到的解决方案应该可以工作。
如果不行,那么我会尝试这样做。假设你有一个User.java类和一个SessionFactory,我认为你可以创建一个像这样的方法:

    public List<User> fetchUsersWithOffsetAndLimit(SessionFactory session, int offset, int limit) {
     List<User> userList = session.getCurrentSession().createQuery(From User)
       .setFirstResult(offset)
       .setMaxResults(limit)
       .list();

     List<User> usersSortedByOrderIdDesc = new ArrayList<>();

     for (int i = userList.size(); i > 0; i--) {
      usersSortedByOrderIdDesc.add(userList.get(i));
     }
    
    return usersSortedByOrderIdDesc;
    }

// SessionFactory sessionFactory = HibernateUtils.getLocSessionFactory();
// Session session = sessionFactory.getCurrentSession();

我添加了可以在参数内调用的SessionFactory。如果你没有在方法调用内传递它,你也可以将它添加到方法内。

可能有一种更有效的方法来做这件事,但我认为这个方法会起作用。

英文:

I think the solution you have above would work.
If not, then I would try this. Assuming you have a User.java class, and a SessionFactory, I believe you can create a method like this:

    public List&lt;User&gt; fetchUsersWithOffsetAndLimit(SessionFactory session, int offset, int limit) {
     List&lt;User&gt; userList = session.getCurrentSession().createQuery(From User)
       .setFirstResult(offset)
       .setMaxResults(limit)
       .list();

     List&lt;User&gt; usersSortedByOrderIdDesc = new ArrayList&lt;&gt;();

     for (int i = userList.size(); i &gt; 0; i--) {
      usersSortedByOrderIdDesc.add(userList.get(i));
     }
    
    return usersSortedByOrderIdDesc;
    }

// SessionFactory sessionFactory = HibernateUtils.getLocSessionFactory();
// Session session = sessionFactory.getCurrentSession();

I added the SessionFactory that can be called within the parameter. It can be added within the method if you are not passing it inside the method call.

There may be a more efficient way of doing it but I think this will work.

huangapple
  • 本文由 发表于 2023年6月6日 02:13:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/76409001.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定