diff --git a/documentation/src/main/asciidoc/introduction/Interacting.adoc b/documentation/src/main/asciidoc/introduction/Interacting.adoc
index 5b55f37475..75bce41199 100644
--- a/documentation/src/main/asciidoc/introduction/Interacting.adoc
+++ b/documentation/src/main/asciidoc/introduction/Interacting.adoc
@@ -900,7 +900,7 @@ Unfortunately, there's no way to do this using JPA's `TypedQuery` interface.
| `setFirstResult()` | Set an offset on the results returned by a query | ✔
| `ascending()` | Add a field to use to order the results | ✖
| `descending()` | Add a field to use to order the results | ✖
-| `unordered()` | Clear any current ordering | ✖
+| `clearOrder()` | Clear any current ordering | ✖
|===
[[projection-lists]]
diff --git a/hibernate-core/src/main/java/org/hibernate/query/Page.java b/hibernate-core/src/main/java/org/hibernate/query/Page.java
new file mode 100644
index 0000000000..c70da3859b
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/query/Page.java
@@ -0,0 +1,63 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later
+ * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
+ */
+package org.hibernate.query;
+
+/**
+ * Identifies a page of query results by {@linkplain #size page size}
+ * and {@linkplain #number page number}.
+ *
+ * This is a convenience class which allows a reference to a page of
+ * results to be passed around the system before being applied to
+ * a {@link Query} by calling {@link Query#paginate(Page)}.
+ *
+ * @see Query#paginate(Page)
+ *
+ * @since 6.3
+ *
+ * @author Gavin King
+ */
+public class Page {
+ private final int size;
+ private final int number;
+
+ public int getSize() {
+ return size;
+ }
+
+ public int getNumber() {
+ return number;
+ }
+
+ public int getMaxResults() {
+ return size;
+ }
+
+ public int getFirstResult() {
+ return size*number;
+ }
+
+ public Page(int size, int number) {
+ this.size = size;
+ this.number = number;
+ }
+
+ public static Page first(int size) {
+ return new Page(0, size);
+ }
+
+ public Page next() {
+ return new Page( size, number+1 );
+ }
+
+ public Page previous() {
+ return new Page( size, number+1 );
+ }
+
+ public Page first() {
+ return first( size );
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/query/Query.java b/hibernate-core/src/main/java/org/hibernate/query/Query.java
index 4b85b33a31..4961f89bca 100644
--- a/hibernate-core/src/main/java/org/hibernate/query/Query.java
+++ b/hibernate-core/src/main/java/org/hibernate/query/Query.java
@@ -290,7 +290,6 @@ public interface Query extends SelectionQuery, MutationQuery, TypedQuery applyLoadGraph(@SuppressWarnings("rawtypes") RootGraph graph) {
return applyGraph( graph, GraphSemantic.LOAD );
}
@@ -890,6 +889,20 @@ public interface Query extends SelectionQuery, MutationQuery, TypedQuery setFirstResult(int startPosition);
+ @Override
+ default Query paginate(int pageSize, int pageNumber) {
+ setFirstResult( pageNumber * pageSize );
+ setMaxResults( pageSize );
+ return this;
+ }
+
+ @Override
+ default Query paginate(Page page) {
+ setMaxResults( page.getMaxResults() );
+ setFirstResult( page.getFirstResult() );
+ return this;
+ }
+
@Override
Query setHint(String hintName, Object value);
diff --git a/hibernate-core/src/main/java/org/hibernate/query/SelectionQuery.java b/hibernate-core/src/main/java/org/hibernate/query/SelectionQuery.java
index b37bb8990a..a7df1200ab 100644
--- a/hibernate-core/src/main/java/org/hibernate/query/SelectionQuery.java
+++ b/hibernate-core/src/main/java/org/hibernate/query/SelectionQuery.java
@@ -316,16 +316,37 @@ public interface SelectionQuery extends CommonQueryContract {
/**
* The first row position to return from the query results. Applied
- * to the SQL query
+ * to the SQL query.
*/
int getFirstResult();
/**
* Set the first row position to return from the query results. Applied
- * to the SQL query
+ * to the SQL query.
*/
SelectionQuery setFirstResult(int startPosition);
+ /**
+ * Set the page of results to return.
+ *
+ * @param pageNumber the page to return, where pages are numbered from zero
+ * @param pageSize the number of results per page
+ *
+ * @since 6.3
+ */
+ @Incubating
+ SelectionQuery paginate(int pageSize, int pageNumber);
+
+ /**
+ * Set the {@linkplain Page page} of results to return.
+ *
+ * @see Page
+ *
+ * @since 6.3
+ */
+ @Incubating
+ SelectionQuery paginate(Page page);
+
/**
* Obtain the {@link CacheMode} in effect for this query. By default,
* the query inherits the {@link CacheMode} of the session from which
@@ -510,6 +531,8 @@ public interface SelectionQuery extends CommonQueryContract {
*
* @param sorts one or more instances of {@link Sort}
*
+ * @see Sort
+ *
* @since 6.3
*/
@Incubating
diff --git a/hibernate-core/src/main/java/org/hibernate/query/Sort.java b/hibernate-core/src/main/java/org/hibernate/query/Sort.java
index 087e7027ee..148a69ee54 100644
--- a/hibernate-core/src/main/java/org/hibernate/query/Sort.java
+++ b/hibernate-core/src/main/java/org/hibernate/query/Sort.java
@@ -1,3 +1,9 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later
+ * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
+ */
package org.hibernate.query;
import jakarta.persistence.metamodel.SingularAttribute;
@@ -18,77 +24,77 @@ import jakarta.persistence.metamodel.SingularAttribute;
* @since 6.3
*/
public class Sort {
- private final SortOrder order;
- private final SingularAttribute attribute;
- private final Class entityClass;
- private final String attributeName;
+ private final SortOrder order;
+ private final SingularAttribute attribute;
+ private final Class entityClass;
+ private final String attributeName;
- public Sort(SortOrder order, SingularAttribute attribute) {
- this.order = order;
- this.attribute = attribute;
- this.attributeName = attribute.getName();
- this.entityClass = attribute.getDeclaringType().getJavaType();
- }
+ public Sort(SortOrder order, SingularAttribute attribute) {
+ this.order = order;
+ this.attribute = attribute;
+ this.attributeName = attribute.getName();
+ this.entityClass = attribute.getDeclaringType().getJavaType();
+ }
- public Sort(SortOrder order, Class entityClass, String attributeName) {
- this.order = order;
- this.entityClass = entityClass;
- this.attributeName = attributeName;
- this.attribute = null;
- }
+ public Sort(SortOrder order, Class entityClass, String attributeName) {
+ this.order = order;
+ this.entityClass = entityClass;
+ this.attributeName = attributeName;
+ this.attribute = null;
+ }
- public static Sort asc(SingularAttribute attribute) {
- return new Sort<>(SortOrder.ASCENDING, attribute);
- }
+ public static Sort asc(SingularAttribute attribute) {
+ return new Sort<>(SortOrder.ASCENDING, attribute);
+ }
- public static Sort desc(SingularAttribute attribute) {
- return new Sort<>(SortOrder.ASCENDING, attribute);
- }
+ public static Sort desc(SingularAttribute attribute) {
+ return new Sort<>(SortOrder.ASCENDING, attribute);
+ }
- public static Sort asc(Class entityClass, String attributeName) {
- return new Sort<>( SortOrder.ASCENDING, entityClass, attributeName );
- }
+ public static Sort asc(Class entityClass, String attributeName) {
+ return new Sort<>( SortOrder.ASCENDING, entityClass, attributeName );
+ }
- public static Sort desc(Class entityClass, String attributeName) {
- return new Sort<>( SortOrder.ASCENDING, entityClass, attributeName );
- }
+ public static Sort desc(Class entityClass, String attributeName) {
+ return new Sort<>( SortOrder.ASCENDING, entityClass, attributeName );
+ }
- public SortOrder getOrder() {
- return order;
- }
+ public SortOrder getOrder() {
+ return order;
+ }
- public SingularAttribute getAttribute() {
- return attribute;
- }
+ public SingularAttribute getAttribute() {
+ return attribute;
+ }
- public Class getEntityClass() {
- return entityClass;
- }
+ public Class getEntityClass() {
+ return entityClass;
+ }
- public String getAttributeName() {
- return attributeName;
- }
+ public String getAttributeName() {
+ return attributeName;
+ }
- @Override
- public String toString() {
- return attributeName + " " + order;
- }
+ @Override
+ public String toString() {
+ return attributeName + " " + order;
+ }
- @Override
- public boolean equals(Object o) {
- if ( o instanceof Sort ) {
- Sort> that = (Sort>) o;
- return that.order == order
- && that.attributeName.equals(attributeName)
- && that.entityClass.equals(entityClass);
- }
- else {
- return false;
- }
- }
+ @Override
+ public boolean equals(Object o) {
+ if ( o instanceof Sort ) {
+ Sort> that = (Sort>) o;
+ return that.order == order
+ && that.attributeName.equals(attributeName)
+ && that.entityClass.equals(entityClass);
+ }
+ else {
+ return false;
+ }
+ }
- @Override
- public int hashCode() {
- return attributeName.hashCode() + entityClass.hashCode();
- }
+ @Override
+ public int hashCode() {
+ return attributeName.hashCode() + entityClass.hashCode();
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java
index 5a336aae9c..4a4e09df91 100644
--- a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java
+++ b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java
@@ -118,7 +118,6 @@ public abstract class AbstractQuery
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// QueryOptions handling
-
@Override
public QueryImplementor setHint(String hintName, Object value) {
super.setHint( hintName, value );
diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractSelectionQuery.java b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractSelectionQuery.java
index 417c7dcd3c..b7c71833e9 100644
--- a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractSelectionQuery.java
+++ b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractSelectionQuery.java
@@ -618,13 +618,10 @@ public abstract class AbstractSelectionQuery
@Override
public SelectionQuery setFirstResult(int startPosition) {
getSession().checkOpen();
-
if ( startPosition < 0 ) {
throw new IllegalArgumentException( "first-result value cannot be negative : " + startPosition );
}
-
getQueryOptions().getLimit().setFirstRow( startPosition );
-
return this;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmSelectionQueryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmSelectionQueryImpl.java
index 6dcb748076..6755aa8c71 100644
--- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmSelectionQueryImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmSelectionQueryImpl.java
@@ -35,7 +35,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.graph.spi.AppliedGraph;
import org.hibernate.internal.util.collections.IdentitySet;
import org.hibernate.query.BindableType;
-import org.hibernate.query.Query;
+import org.hibernate.query.Page;
import org.hibernate.query.QueryLogging;
import org.hibernate.query.QueryParameter;
import org.hibernate.query.SelectionQuery;
@@ -279,6 +279,37 @@ public class SqmSelectionQueryImpl extends AbstractSelectionQuery
return hql;
}
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // convenience methods
+
+ @Override
+ public SelectionQuery paginate(int pageSize, int pageNumber) {
+ setFirstResult( pageNumber * pageSize );
+ setMaxResults( pageSize );
+ return this;
+ }
+
+ @Override
+ public SelectionQuery paginate(Page page) {
+ setMaxResults( page.getMaxResults() );
+ setFirstResult( page.getFirstResult() );
+ return this;
+ }
+
+ @Override @SafeVarargs
+ public final SelectionQuery sort(Sort super R>... sorts) {
+ for (Sort super R> sort: sorts) {
+ SingularAttribute super R,?> attribute = sort.getAttribute();
+ if ( attribute == null ) {
+ attribute =
+ getSession().getFactory().getMetamodel()
+ .entity( sort.getEntityClass() )
+ .getSingularAttribute( sort.getAttributeName() );
+ }
+ sort( sort.getOrder(), attribute );
+ }
+ return this;
+ }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// execution
@@ -578,21 +609,6 @@ public class SqmSelectionQueryImpl extends AbstractSelectionQuery
return null;
}
- @Override @SafeVarargs
- public final SqmSelectionQuery sort(Sort super R>... sorts) {
- for (Sort super R> sort: sorts) {
- SingularAttribute super R,?> attribute = sort.getAttribute();
- if ( attribute == null ) {
- attribute =
- getSession().getFactory().getMetamodel()
- .entity( sort.getEntityClass() )
- .getSingularAttribute( sort.getAttributeName() );
- }
- sort( sort.getOrder(), attribute );
- }
- return this;
- }
-
@Override
public SqmSelectionQuery ascending(int element) {
addOrdering( element, SortOrder.ASCENDING );