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... sorts) { + for (Sort sort: sorts) { + SingularAttribute 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... sorts) { - for (Sort sort: sorts) { - SingularAttribute 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 );