From 20c22883d7af69416592b055091a7be8d15f986a Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 15 Apr 2025 18:50:32 +0200 Subject: [PATCH 1/4] Add JPA Criteria API extension for adding Restriction, Order and allow fluent construction of Query from CriteriaQuery --- .../engine/spi/SessionDelegatorBaseImpl.java | 6 + .../engine/spi/SessionLazyDelegator.java | 6 + .../spi/SharedSessionDelegatorBaseImpl.java | 6 + .../AbstractSharedSessionContract.java | 5 + .../org/hibernate/query/QueryProducer.java | 14 ++ .../query/criteria/CriteriaDefinition.java | 16 ++ .../query/criteria/JpaCriteriaQuery.java | 57 +++++++ .../hibernate/query/sqm/internal/SqmUtil.java | 2 +- .../sqm/tree/select/SqmSelectStatement.java | 22 +++ ...ndFetchWithCriteriaSelectionQueryTest.java | 18 ++- .../orm/test/query/order/OrderTest.java | 146 +++++++++++------- .../query/restriction/RestrictionTest.java | 69 ++++++--- 12 files changed, 283 insertions(+), 84 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java index 83f8cd0f2128..1abff79c1de7 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java @@ -49,6 +49,7 @@ import org.hibernate.query.SelectionQuery; import org.hibernate.query.criteria.HibernateCriteriaBuilder; import org.hibernate.query.criteria.JpaCriteriaInsert; +import org.hibernate.query.criteria.JpaCriteriaQuery; import org.hibernate.query.spi.QueryImplementor; import org.hibernate.query.spi.QueryProducerImplementor; import org.hibernate.query.sql.spi.NativeQueryImplementor; @@ -587,6 +588,11 @@ public SelectionQuery createSelectionQuery(String hqlString, EntityGraph< return queryDelegate().createSelectionQuery( hqlString, resultGraph ); } + @Override + public JpaCriteriaQuery createSelectionCriteria(String hqlString, Class resultClass) { + return queryDelegate().createSelectionCriteria( hqlString, resultClass ); + } + @Override public SelectionQuery createSelectionQuery(CriteriaQuery criteria) { return queryDelegate().createSelectionQuery( criteria ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java index d1aeeca586f8..5df52240c896 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java @@ -41,6 +41,7 @@ import org.hibernate.query.SelectionQuery; import org.hibernate.query.criteria.HibernateCriteriaBuilder; import org.hibernate.query.criteria.JpaCriteriaInsert; +import org.hibernate.query.criteria.JpaCriteriaQuery; import org.hibernate.stat.SessionStatistics; import jakarta.persistence.ConnectionConsumer; @@ -704,6 +705,11 @@ public SelectionQuery createSelectionQuery(String hqlString, EntityGraph< return this.lazySession.get().createSelectionQuery( hqlString, resultGraph ); } + @Override + public JpaCriteriaQuery createSelectionCriteria(String hqlString, Class resultClass) { + return this.lazySession.get().createSelectionCriteria( hqlString, resultClass ); + } + @Override public SelectionQuery createSelectionQuery(CriteriaQuery criteria) { return this.lazySession.get().createSelectionQuery( criteria ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java index 4934be8b4cb8..890c7a435e2e 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java @@ -37,6 +37,7 @@ import org.hibernate.query.SelectionQuery; import org.hibernate.query.criteria.HibernateCriteriaBuilder; import org.hibernate.query.criteria.JpaCriteriaInsert; +import org.hibernate.query.criteria.JpaCriteriaQuery; import org.hibernate.query.spi.QueryImplementor; import org.hibernate.query.spi.QueryProducerImplementor; import org.hibernate.query.sql.spi.NativeQueryImplementor; @@ -154,6 +155,11 @@ public SelectionQuery createSelectionQuery(String hqlString, EntityGraph< return queryDelegate().createSelectionQuery( hqlString, resultGraph ); } + @Override + public JpaCriteriaQuery createSelectionCriteria(String hqlString, Class resultClass) { + return queryDelegate().createSelectionCriteria( hqlString, resultClass ); + } + @Override public SelectionQuery createSelectionQuery(CriteriaQuery criteria) { return queryDelegate().createSelectionQuery( criteria ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index fa181cabfa96..d6c6ee48dc97 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -75,6 +75,7 @@ import org.hibernate.query.criteria.CriteriaDefinition; import org.hibernate.query.criteria.HibernateCriteriaBuilder; import org.hibernate.query.criteria.JpaCriteriaInsert; +import org.hibernate.query.criteria.JpaCriteriaQuery; import org.hibernate.query.hql.spi.SqmQueryImplementor; import org.hibernate.query.named.NamedObjectRepository; import org.hibernate.query.named.NamedResultSetMappingMemento; @@ -871,6 +872,10 @@ public SelectionQuery createSelectionQuery(String hqlString, EntityGraph< .setEntityGraph( resultGraph, GraphSemantic.LOAD ); } + @Override + public JpaCriteriaQuery createSelectionCriteria(String hqlString, Class resultClass) { + return getCriteriaBuilder().createQuery(hqlString, resultClass); + } @Override public SelectionQuery createSelectionQuery(CriteriaQuery criteria) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java b/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java index 09dff40648c7..91c0fd3216ae 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java +++ b/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java @@ -11,6 +11,7 @@ import jakarta.persistence.criteria.CriteriaDelete; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaUpdate; +import org.hibernate.query.criteria.JpaCriteriaQuery; /** * Contract for things that can produce instances of {@link Query} and {@link NativeQuery}. @@ -377,6 +378,19 @@ public interface QueryProducer { */ SelectionQuery createSelectionQuery(String hqlString, EntityGraph resultGraph); + /** + * Transform the given HQL {@code select} query to an equivalent criteria query. + * + * @param hqlString The HQL {@code select} query + * @param resultClass The result type of the query + * + * @see org.hibernate.query.criteria.HibernateCriteriaBuilder#createQuery(String, Class) + * + * @since 7.0 + */ + @Incubating + JpaCriteriaQuery createSelectionCriteria(String hqlString, Class resultClass); + /** * Create a {@link SelectionQuery} reference for the given * {@link CriteriaQuery}. diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/CriteriaDefinition.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/CriteriaDefinition.java index 8845911781e3..cf5a10c3cf40 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/CriteriaDefinition.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/CriteriaDefinition.java @@ -16,6 +16,7 @@ import org.hibernate.query.SelectionQuery; import org.hibernate.query.criteria.spi.HibernateCriteriaBuilderDelegate; import org.hibernate.query.common.FetchClauseType; +import org.hibernate.query.restriction.Restriction; import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; @@ -495,4 +496,19 @@ public JpaFunctionRoot from(JpaSetReturningFunction function) { public JpaCriteriaQuery createCountQuery() { return query.createCountQuery(); } + + @Override + public JpaCriteriaQuery setOrder(List> orderList) { + return query.setOrder( orderList ); + } + + @Override + public JpaCriteriaQuery setOrder(org.hibernate.query.Order order) { + return query.setOrder( order ); + } + + @Override + public JpaCriteriaQuery addRestriction(Restriction restriction) { + return query.addRestriction( restriction ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaCriteriaQuery.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaCriteriaQuery.java index e87c0fbb7a81..bc26477a80e6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaCriteriaQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaCriteriaQuery.java @@ -7,6 +7,9 @@ import java.util.List; import java.util.Set; +import org.hibernate.Incubating; +import org.hibernate.SharedSessionContract; +import org.hibernate.query.Query; import org.hibernate.query.common.FetchClauseType; import jakarta.persistence.criteria.CriteriaQuery; @@ -17,6 +20,7 @@ import jakarta.persistence.criteria.Root; import jakarta.persistence.criteria.Selection; import jakarta.persistence.metamodel.EntityType; +import org.hibernate.query.restriction.Restriction; /** * Extension of the JPA {@link CriteriaQuery} @@ -34,6 +38,59 @@ public interface JpaCriteriaQuery extends CriteriaQuery, JpaQueryableCrite */ JpaCriteriaQuery createCountQuery(); + /** + * If the result type of this query is an entity class, add one or more + * {@linkplain org.hibernate.query.Order rules} for ordering the query results. + * + * @param orderList one or more instances of {@link org.hibernate.query.Order} + * + * @see org.hibernate.query.Order + * + * @since 7.0 + */ + @Incubating + JpaCriteriaQuery setOrder(List> orderList); + + /** + * If the result type of this query is an entity class, add a + * {@linkplain org.hibernate.query.Order rule} for ordering the query results. + * + * @param order an instance of {@link org.hibernate.query.Order} + * + * @see org.hibernate.query.Order + * + * @since 7.0 + */ + @Incubating + JpaCriteriaQuery setOrder(org.hibernate.query.Order order); + + /** + * If the result type of this query is an entity class, add a + * {@linkplain Restriction rule} for restricting the query results. + * + * @param restriction an instance of {@link Restriction} + * + * @see Restriction + * + * @since 7.0 + */ + @Incubating + JpaCriteriaQuery addRestriction(Restriction restriction); + + /** + * Creates a query for this criteria query. + * + * @param session the Hibernate session + * + * @see SharedSessionContract#createQuery(CriteriaQuery) + * + * @since 7.0 + */ + @Incubating + default Query toQuery(SharedSessionContract session) { + return session.createQuery( this ); + } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Limit/Offset/Fetch clause diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java index 26572aa7de10..5518d199b631 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java @@ -841,7 +841,7 @@ public Map, SqmJpaCriteriaParameterWrapper> getJpaCri } } - static JpaOrder sortSpecification(SqmSelectStatement sqm, Order order) { + public static JpaOrder sortSpecification(SqmSelectStatement sqm, Order order) { final List> items = sqm.getQuerySpec().getSelectClause().getSelectionItems(); final int element = order.getElement(); if ( element < 1) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java index 9a6630ae57d9..a93428e6bb59 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java @@ -17,6 +17,7 @@ import org.hibernate.query.criteria.JpaExpression; import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.common.FetchClauseType; +import org.hibernate.query.restriction.Restriction; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SqmQuerySource; @@ -43,6 +44,8 @@ import static java.util.Collections.emptySet; import static java.util.Collections.unmodifiableList; import static java.util.Collections.unmodifiableSet; +import static java.util.stream.Collectors.toList; +import static org.hibernate.query.sqm.internal.SqmUtil.sortSpecification; import static org.hibernate.query.sqm.spi.SqmCreationHelper.combinePredicates; import static org.hibernate.query.sqm.SqmQuerySource.CRITERIA; import static org.hibernate.query.sqm.tree.SqmCopyContext.noParamCopyContext; @@ -553,6 +556,25 @@ public SqmSelectStatement createCountQuery() { } } + @Override + public JpaCriteriaQuery setOrder(List> orderList) { + orderBy( orderList.stream().map( order -> sortSpecification( this, order ) ) + .collect( toList() ) ); + return this; + } + + @Override + public JpaCriteriaQuery setOrder(org.hibernate.query.Order order) { + orderBy( sortSpecification( this, order ) ); + return this; + } + + @Override + public JpaCriteriaQuery addRestriction(Restriction restriction) { + restriction.apply( this, this.getRoot( 0, getResultType() ) ); + return this; + } + private void aliasSelections(SqmQueryPart queryPart) { if ( queryPart.isSimpleQueryPart() ) { final SqmQuerySpec querySpec = queryPart.getFirstQuerySpec(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/join/JoinAndFetchWithCriteriaSelectionQueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/join/JoinAndFetchWithCriteriaSelectionQueryTest.java index 683b83515a17..2590945921ea 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/join/JoinAndFetchWithCriteriaSelectionQueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/join/JoinAndFetchWithCriteriaSelectionQueryTest.java @@ -12,6 +12,8 @@ import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.query.Order; +import org.hibernate.query.criteria.HibernateCriteriaBuilder; +import org.hibernate.query.criteria.JpaCriteriaQuery; import org.hibernate.testing.jdbc.SQLStatementInspector; import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.Jira; @@ -120,8 +122,8 @@ void fetchAfterJoinWithoutWhereClauseTest(SessionFactoryScope scope) { final SQLStatementInspector inspector = scope.getCollectingStatementInspector(); inspector.clear(); scope.inTransaction( session -> { - CriteriaBuilder cb = session.getCriteriaBuilder(); - CriteriaQuery query = cb.createQuery( Book.class ); + HibernateCriteriaBuilder cb = session.getCriteriaBuilder(); + JpaCriteriaQuery query = cb.createQuery( Book.class ); Root from = query.from( Book.class ); // The join MUST BE created before the fetch for this test @@ -135,9 +137,9 @@ void fetchAfterJoinWithoutWhereClauseTest(SessionFactoryScope scope) { SingularAttribute title = bookType.findSingularAttribute( "title" ); query.select( from ).distinct( true ); - List books = session - .createSelectionQuery( query ) + List books = query .setOrder( Order.asc( title ) ) + .toQuery( session ) .getResultList(); assertThat( books ).containsExactly( leftHand, timeWar ); assertThat( Hibernate.isInitialized( books.get( 0 ).getAuthors() ) ).isTrue(); @@ -154,8 +156,8 @@ void fetchBeforeJoinWithoutWhereClauseTest(SessionFactoryScope scope) { final SQLStatementInspector inspector = scope.getCollectingStatementInspector(); inspector.clear(); scope.inTransaction( session -> { - CriteriaBuilder cb = session.getCriteriaBuilder(); - CriteriaQuery query = cb.createQuery( Book.class ); + HibernateCriteriaBuilder cb = session.getCriteriaBuilder(); + JpaCriteriaQuery query = cb.createQuery( Book.class ); Root from = query.from( Book.class ); // The fetch MUST BE created before the join for this test @@ -169,9 +171,9 @@ void fetchBeforeJoinWithoutWhereClauseTest(SessionFactoryScope scope) { SingularAttribute title = bookType.findSingularAttribute( "title" ); query.select( from ).distinct( true ); - List books = session - .createSelectionQuery( query ) + List books = query .setOrder( Order.asc( title ) ) + .toQuery( session ) .getResultList(); assertThat( books ).containsExactly( leftHand, timeWar ); assertThat( Hibernate.isInitialized( books.get( 0 ).getAuthors() ) ).isTrue(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/order/OrderTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/order/OrderTest.java index 51108f40f731..2808be7da932 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/order/OrderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/order/OrderTest.java @@ -38,48 +38,54 @@ public class OrderTest { SingularAttribute title = bookType.findSingularAttribute("title"); SingularAttribute isbn = bookType.findSingularAttribute("isbn"); scope.inSession(session -> { - List titlesAsc = session.createSelectionQuery("from Book", Book.class) + List titlesAsc = session.createSelectionCriteria("from Book", Book.class) .setOrder(asc(title)) + .toQuery( session ) .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", titlesAsc.get(0)); assertEquals("Java Persistence with Hibernate", titlesAsc.get(1)); - List titlesDesc = session.createSelectionQuery("from Book", Book.class) + List titlesDesc = session.createSelectionCriteria("from Book", Book.class) .setOrder(desc(title)) + .toQuery( session ) .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", titlesDesc.get(1)); assertEquals("Java Persistence with Hibernate", titlesDesc.get(0)); - List isbnAsc = session.createSelectionQuery("from Book", Book.class) + List isbnAsc = session.createSelectionCriteria("from Book", Book.class) .setOrder(List.of(asc(isbn), desc(title))) + .toQuery( session ) .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", isbnAsc.get(1)); assertEquals("Java Persistence with Hibernate", isbnAsc.get(0)); - List isbnDesc = session.createSelectionQuery("from Book", Book.class) + List isbnDesc = session.createSelectionCriteria("from Book", Book.class) .setOrder(List.of(desc(isbn), desc(title))) + .toQuery( session ) .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", isbnDesc.get(0)); assertEquals("Java Persistence with Hibernate", isbnDesc.get(1)); -// titlesAsc = session.createSelectionQuery("from Book order by isbn asc", Book.class) +// titlesAsc = session.createSelectionCriteria("from Book order by isbn asc", Book.class) // .setOrder(asc(title)) +// .toQuery( session ) // .getResultList() // .stream().map(book -> book.title) // .collect(toList()); // assertEquals("Hibernate in Action", titlesAsc.get(1)); // assertEquals("Java Persistence with Hibernate", titlesAsc.get(0)); - titlesAsc = session.createSelectionQuery("from Book order by isbn asc", Book.class) + titlesAsc = session.createSelectionCriteria("from Book order by isbn asc", Book.class) // .setOrder(emptyList()) .setOrder(asc(title)) + .toQuery( session ) .getResultList() .stream().map(book -> book.title) .collect(toList()); @@ -98,54 +104,60 @@ public class OrderTest { SingularAttribute title = bookType.findSingularAttribute("title"); SingularAttribute isbn = bookType.findSingularAttribute("isbn"); scope.inSession(session -> { - List titlesAsc = session.createSelectionQuery("from Book where title like ?1", Book.class) - .setParameter(1, "%Hibernate%") + List titlesAsc = session.createSelectionCriteria("from Book where title like ?1", Book.class) .setOrder(asc(title)) + .toQuery( session ) + .setParameter(1, "%Hibernate%") .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", titlesAsc.get(0)); assertEquals("Java Persistence with Hibernate", titlesAsc.get(1)); - List titlesDesc = session.createSelectionQuery("from Book where title like ?1", Book.class) - .setParameter(1, "%Hibernate%") + List titlesDesc = session.createSelectionCriteria("from Book where title like ?1", Book.class) .setOrder(Order.desc(title)) + .toQuery( session ) + .setParameter(1, "%Hibernate%") .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", titlesDesc.get(1)); assertEquals("Java Persistence with Hibernate", titlesDesc.get(0)); - List isbnAsc = session.createSelectionQuery("from Book where title like ?1", Book.class) - .setParameter(1, "%Hibernate%") + List isbnAsc = session.createSelectionCriteria("from Book where title like ?1", Book.class) .setOrder(List.of(asc(isbn), desc(title))) + .toQuery( session ) + .setParameter(1, "%Hibernate%") .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", isbnAsc.get(1)); assertEquals("Java Persistence with Hibernate", isbnAsc.get(0)); - List isbnDesc = session.createSelectionQuery("from Book where title like ?1", Book.class) - .setParameter(1, "%Hibernate%") + List isbnDesc = session.createSelectionCriteria("from Book where title like ?1", Book.class) .setOrder(List.of(desc(isbn), desc(title))) + .toQuery( session ) + .setParameter(1, "%Hibernate%") .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", isbnDesc.get(0)); assertEquals("Java Persistence with Hibernate", isbnDesc.get(1)); -// titlesAsc = session.createSelectionQuery("from Book where title like ?1 order by isbn asc", Book.class) +// titlesAsc = session.createSelectionCriteria("from Book where title like ?1 order by isbn asc", Book.class) // .setParameter(1, "%Hibernate%") // .setOrder(asc(title)) +// .toQuery( session ) // .getResultList() // .stream().map(book -> book.title) // .collect(toList()); // assertEquals("Hibernate in Action", titlesAsc.get(1)); // assertEquals("Java Persistence with Hibernate", titlesAsc.get(0)); - titlesAsc = session.createSelectionQuery("from Book where title like ?1 order by isbn asc", Book.class) - .setParameter(1, "%Hibernate%") + titlesAsc = session.createSelectionCriteria("from Book where title like ?1 order by isbn asc", Book.class) // .setOrder(emptyList()) .setOrder(asc(title)) + .toQuery( session ) + .setParameter(1, "%Hibernate%") .getResultList() .stream().map(book -> book.title) .collect(toList()); @@ -164,54 +176,60 @@ public class OrderTest { SingularAttribute title = bookType.findSingularAttribute("title"); SingularAttribute isbn = bookType.findSingularAttribute("isbn"); scope.inSession(session -> { - List titlesAsc = session.createSelectionQuery("from Book where title like :title", Book.class) - .setParameter("title", "%Hibernate%") + List titlesAsc = session.createSelectionCriteria("from Book where title like :title", Book.class) .setOrder(asc(title)) + .toQuery( session ) + .setParameter("title", "%Hibernate%") .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", titlesAsc.get(0)); assertEquals("Java Persistence with Hibernate", titlesAsc.get(1)); - List titlesDesc = session.createSelectionQuery("from Book where title like :title", Book.class) - .setParameter("title", "%Hibernate%") + List titlesDesc = session.createSelectionCriteria("from Book where title like :title", Book.class) .setOrder(desc(title)) + .toQuery( session ) + .setParameter("title", "%Hibernate%") .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", titlesDesc.get(1)); assertEquals("Java Persistence with Hibernate", titlesDesc.get(0)); - List isbnAsc = session.createSelectionQuery("from Book where title like :title", Book.class) - .setParameter("title", "%Hibernate%") + List isbnAsc = session.createSelectionCriteria("from Book where title like :title", Book.class) .setOrder(List.of(asc(isbn), desc(title))) + .toQuery( session ) + .setParameter("title", "%Hibernate%") .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", isbnAsc.get(1)); assertEquals("Java Persistence with Hibernate", isbnAsc.get(0)); - List isbnDesc = session.createSelectionQuery("from Book where title like :title", Book.class) - .setParameter("title", "%Hibernate%") + List isbnDesc = session.createSelectionCriteria("from Book where title like :title", Book.class) .setOrder(List.of(desc(isbn), desc(title))) + .toQuery( session ) + .setParameter("title", "%Hibernate%") .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", isbnDesc.get(0)); assertEquals("Java Persistence with Hibernate", isbnDesc.get(1)); -// titlesAsc = session.createSelectionQuery("from Book where title like :title order by isbn asc", Book.class) +// titlesAsc = session.createSelectionCriteria("from Book where title like :title order by isbn asc", Book.class) // .setParameter("title", "%Hibernate%") // .setOrder(asc(title)) +// .toQuery( session ) // .getResultList() // .stream().map(book -> book.title) // .collect(toList()); // assertEquals("Hibernate in Action", titlesAsc.get(1)); // assertEquals("Java Persistence with Hibernate", titlesAsc.get(0)); - titlesAsc = session.createSelectionQuery("from Book where title like :title order by isbn asc", Book.class) + titlesAsc = session.createSelectionCriteria("from Book where title like :title order by isbn asc", Book.class) + .setOrder(asc(title)) + .toQuery( session ) .setParameter("title", "%Hibernate%") // .setOrder(emptyList()) - .setOrder(asc(title)) .getResultList() .stream().map(book -> book.title) .collect(toList()); @@ -227,32 +245,36 @@ public class OrderTest { session.persist(new Book("9781617290459", "Java Persistence with Hibernate")); }); scope.inSession(session -> { - List titlesAsc = session.createSelectionQuery("select isbn, title from Book", Object[].class) + List titlesAsc = session.createSelectionCriteria("select isbn, title from Book", Object[].class) .setOrder(asc(2)) + .toQuery( session ) .getResultList() .stream().map(book -> book[1]) .collect(toList()); assertEquals("Hibernate in Action", titlesAsc.get(0)); assertEquals("Java Persistence with Hibernate", titlesAsc.get(1)); - List titlesDesc = session.createSelectionQuery("select isbn, title from Book", Object[].class) + List titlesDesc = session.createSelectionCriteria("select isbn, title from Book", Object[].class) .setOrder(desc(2)) + .toQuery( session ) .getResultList() .stream().map(book -> book[1]) .collect(toList()); assertEquals("Hibernate in Action", titlesDesc.get(1)); assertEquals("Java Persistence with Hibernate", titlesDesc.get(0)); - List isbnAsc = session.createSelectionQuery("select isbn, title from Book", Object[].class) + List isbnAsc = session.createSelectionCriteria("select isbn, title from Book", Object[].class) .setOrder(List.of(asc(1), desc(2))) + .toQuery( session ) .getResultList() .stream().map(book -> book[1]) .collect(toList()); assertEquals("Hibernate in Action", isbnAsc.get(1)); assertEquals("Java Persistence with Hibernate", isbnAsc.get(0)); - List isbnDesc = session.createSelectionQuery("select isbn, title from Book", Object[].class) + List isbnDesc = session.createSelectionCriteria("select isbn, title from Book", Object[].class) .setOrder(List.of(desc(1), desc(2))) + .toQuery( session ) .getResultList() .stream().map(book -> book[1]) .collect(toList()); @@ -271,48 +293,54 @@ public class OrderTest { SingularAttribute title = bookType.findSingularAttribute("title"); SingularAttribute isbn = bookType.findSingularAttribute("isbn"); scope.inSession(session -> { - List titlesAsc = session.createSelectionQuery("from Book", Book.class) + List titlesAsc = session.createSelectionCriteria("from Book", Book.class) .setOrder(asc(title).ignoringCase()) + .toQuery( session ) .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", titlesAsc.get(0)); assertEquals("Java Persistence with Hibernate", titlesAsc.get(1)); - List titlesDesc = session.createSelectionQuery("from Book", Book.class) + List titlesDesc = session.createSelectionCriteria("from Book", Book.class) .setOrder(desc(title).ignoringCase()) + .toQuery( session ) .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", titlesDesc.get(1)); assertEquals("Java Persistence with Hibernate", titlesDesc.get(0)); - List isbnAsc = session.createSelectionQuery("from Book", Book.class) + List isbnAsc = session.createSelectionCriteria("from Book", Book.class) .setOrder(List.of(asc(isbn).ignoringCase(), desc(title).ignoringCase())) + .toQuery( session ) .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", isbnAsc.get(1)); assertEquals("Java Persistence with Hibernate", isbnAsc.get(0)); - List isbnDesc = session.createSelectionQuery("from Book", Book.class) + List isbnDesc = session.createSelectionCriteria("from Book", Book.class) .setOrder(List.of(desc(isbn).ignoringCase(), desc(title).ignoringCase())) + .toQuery( session ) .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", isbnDesc.get(0)); assertEquals("Java Persistence with Hibernate", isbnDesc.get(1)); -// titlesAsc = session.createSelectionQuery("from Book order by isbn asc", Book.class) +// titlesAsc = session.createSelectionCriteria("from Book order by isbn asc", Book.class) // .setOrder(asc(title)) +// .toQuery( session ) // .getResultList() // .stream().map(book -> book.title) // .collect(toList()); // assertEquals("Hibernate in Action", titlesAsc.get(1)); // assertEquals("Java Persistence with Hibernate", titlesAsc.get(0)); - titlesAsc = session.createSelectionQuery("from Book order by isbn asc", Book.class) + titlesAsc = session.createSelectionCriteria("from Book order by isbn asc", Book.class) // .setOrder(emptyList()) .setOrder(asc(title).ignoringCase()) + .toQuery( session ) .getResultList() .stream().map(book -> book.title) .collect(toList()); @@ -331,48 +359,54 @@ public class OrderTest { SingularAttribute title = bookType.findSingularAttribute("title"); SingularAttribute isbn = bookType.findSingularAttribute("isbn"); scope.inSession(session -> { - List titlesAsc = session.createSelectionQuery("from Book", Book.class) + List titlesAsc = session.createSelectionCriteria("from Book", Book.class) .setOrder(by(title, ASCENDING, true)) + .toQuery( session ) .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", titlesAsc.get(0)); assertEquals("Java Persistence with Hibernate", titlesAsc.get(1)); - List titlesDesc = session.createSelectionQuery("from Book", Book.class) + List titlesDesc = session.createSelectionCriteria("from Book", Book.class) .setOrder(by(title, DESCENDING, true)) + .toQuery( session ) .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", titlesDesc.get(1)); assertEquals("Java Persistence with Hibernate", titlesDesc.get(0)); - List isbnAsc = session.createSelectionQuery("from Book", Book.class) + List isbnAsc = session.createSelectionCriteria("from Book", Book.class) .setOrder(List.of(by(isbn, ASCENDING, true), by(title, DESCENDING, true))) + .toQuery( session ) .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", isbnAsc.get(1)); assertEquals("Java Persistence with Hibernate", isbnAsc.get(0)); - List isbnDesc = session.createSelectionQuery("from Book", Book.class) + List isbnDesc = session.createSelectionCriteria("from Book", Book.class) .setOrder(List.of(by(isbn, DESCENDING, true), by(title, DESCENDING, true))) + .toQuery( session ) .getResultList() .stream().map(book -> book.title) .collect(toList()); assertEquals("Hibernate in Action", isbnDesc.get(0)); assertEquals("Java Persistence with Hibernate", isbnDesc.get(1)); -// titlesAsc = session.createSelectionQuery("from Book order by isbn asc", Book.class) +// titlesAsc = session.createSelectionCriteria("from Book order by isbn asc", Book.class) // .setOrder(asc(title)) +// .toQuery( session ) // .getResultList() // .stream().map(book -> book.title) // .collect(toList()); // assertEquals("Hibernate in Action", titlesAsc.get(1)); // assertEquals("Java Persistence with Hibernate", titlesAsc.get(0)); - titlesAsc = session.createSelectionQuery("from Book order by isbn asc", Book.class) + titlesAsc = session.createSelectionCriteria("from Book order by isbn asc", Book.class) // .setOrder(emptyList()) .setOrder(by(title, ASCENDING, true)) + .toQuery( session ) .getResultList() .stream().map(book -> book.title) .collect(toList()); @@ -388,32 +422,36 @@ public class OrderTest { session.persist(new Book("9781617290459", "Java Persistence with Hibernate")); }); scope.inSession(session -> { - List titlesAsc = session.createSelectionQuery("select isbn, title from Book", Object[].class) + List titlesAsc = session.createSelectionCriteria("select isbn, title from Book", Object[].class) .setOrder(asc(2).ignoringCase()) + .toQuery( session ) .getResultList() .stream().map(book -> book[1]) .collect(toList()); assertEquals("Hibernate in Action", titlesAsc.get(0)); assertEquals("Java Persistence with Hibernate", titlesAsc.get(1)); - List titlesDesc = session.createSelectionQuery("select isbn, title from Book", Object[].class) + List titlesDesc = session.createSelectionCriteria("select isbn, title from Book", Object[].class) .setOrder(desc(2).ignoringCase()) + .toQuery( session ) .getResultList() .stream().map(book -> book[1]) .collect(toList()); assertEquals("Hibernate in Action", titlesDesc.get(1)); assertEquals("Java Persistence with Hibernate", titlesDesc.get(0)); - List isbnAsc = session.createSelectionQuery("select isbn, title from Book", Object[].class) + List isbnAsc = session.createSelectionCriteria("select isbn, title from Book", Object[].class) .setOrder(List.of(asc(1).ignoringCase(), desc(2).ignoringCase())) + .toQuery( session ) .getResultList() .stream().map(book -> book[1]) .collect(toList()); assertEquals("Hibernate in Action", isbnAsc.get(1)); assertEquals("Java Persistence with Hibernate", isbnAsc.get(0)); - List isbnDesc = session.createSelectionQuery("select isbn, title from Book", Object[].class) + List isbnDesc = session.createSelectionCriteria("select isbn, title from Book", Object[].class) .setOrder(List.of(desc(1).ignoringCase(), desc(2).ignoringCase())) + .toQuery( session ) .getResultList() .stream().map(book -> book[1]) .collect(toList()); @@ -429,32 +467,36 @@ public class OrderTest { session.persist(new Book("9781617290459", "Java Persistence with Hibernate")); }); scope.inSession(session -> { - List titlesAsc = session.createSelectionQuery("select isbn, title from Book", Object[].class) + List titlesAsc = session.createSelectionCriteria("select isbn, title from Book", Object[].class) .setOrder(by(2, ASCENDING, true)) + .toQuery( session ) .getResultList() .stream().map(book -> book[1]) .collect(toList()); assertEquals("Hibernate in Action", titlesAsc.get(0)); assertEquals("Java Persistence with Hibernate", titlesAsc.get(1)); - List titlesDesc = session.createSelectionQuery("select isbn, title from Book", Object[].class) + List titlesDesc = session.createSelectionCriteria("select isbn, title from Book", Object[].class) .setOrder(by(2, DESCENDING, true)) + .toQuery( session ) .getResultList() .stream().map(book -> book[1]) .collect(toList()); assertEquals("Hibernate in Action", titlesDesc.get(1)); assertEquals("Java Persistence with Hibernate", titlesDesc.get(0)); - List isbnAsc = session.createSelectionQuery("select isbn, title from Book", Object[].class) + List isbnAsc = session.createSelectionCriteria("select isbn, title from Book", Object[].class) .setOrder(List.of(by(1, ASCENDING, true), by(2, DESCENDING, true))) + .toQuery( session ) .getResultList() .stream().map(book -> book[1]) .collect(toList()); assertEquals("Hibernate in Action", isbnAsc.get(1)); assertEquals("Java Persistence with Hibernate", isbnAsc.get(0)); - List isbnDesc = session.createSelectionQuery("select isbn, title from Book", Object[].class) + List isbnDesc = session.createSelectionCriteria("select isbn, title from Book", Object[].class) .setOrder(List.of(by(1, DESCENDING, true), by(2, DESCENDING, true))) + .toQuery( session ) .getResultList() .stream().map(book -> book[1]) .collect(toList()); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/restriction/RestrictionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/restriction/RestrictionTest.java index 533b7805cd64..d6d159d377fe 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/restriction/RestrictionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/restriction/RestrictionTest.java @@ -57,92 +57,108 @@ void test(SessionFactoryScope scope) { var pages = (SingularAttribute) bookType.findSingularAttribute("pages"); Book book = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class ) + session.createSelectionCriteria( "from Book", Book.class ) .addRestriction( equal( isbn, "9781932394153" ) ) + .toQuery( session ) .getSingleResult() ); assertEquals( "Hibernate in Action", book.title ); List books = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( like( title, "%Hibernate%" ) ) .setOrder( desc( title ) ) + .toQuery( session ) .getResultList() ); assertEquals( 2, books.size() ); assertEquals( "Java Persistence with Hibernate", books.get(0).title ); assertEquals( "Hibernate in Action", books.get(1).title ); List booksByIsbn = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( in( isbn, List.of("9781932394153", "9781617290459") ) ) .setOrder( asc( title ) ) + .toQuery( session ) .getResultList() ); assertEquals( 2, booksByIsbn.size() ); assertEquals( "Hibernate in Action", booksByIsbn.get(0).title ); assertEquals( "Java Persistence with Hibernate", booksByIsbn.get(1).title ); List booksByPages = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( greaterThan( pages, 500 ) ) + .toQuery( session ) .getResultList() ); assertEquals( 1, booksByPages.size() ); List booksByPageRange = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( between( pages, 150, 400 ) ) + .toQuery( session ) .getResultList() ); assertEquals( 1, booksByPageRange.size() ); Book bookByTitle = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( equalIgnoringCase( title, "hibernate in action" ) ) + .toQuery( session ) .getSingleResultOrNull() ); assertEquals( "9781932394153", bookByTitle.isbn ); Book bookByTitleUnsafe = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( restrict( Book.class, "title", singleCaseInsensitiveValue("hibernate in action") ) ) + .toQuery( session ) .getSingleResultOrNull() ); assertEquals( "9781932394153", bookByTitleUnsafe.isbn ); List allBooks = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( unrestricted() ) + .toQuery( session ) .getResultList() ); assertEquals( 2, allBooks.size() ); List noBooks = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( unrestricted().negated() ) + .toQuery( session ) .getResultList() ); assertEquals( 0, noBooks.size() ); List books1 = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( endsWith(title, "Hibernate") ) + .toQuery( session ) .getResultList() ); assertEquals( 1, books1.size() ); List books2 = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( like(title, "*Hibernat?", false, '?', '*') ) + .toQuery( session ) .getResultList() ); assertEquals( 1, books2.size() ); List books3 = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( contains(title, "Hibernate") ) + .toQuery( session ) .getResultList() ); assertEquals( 2, books3.size() ); List booksByTitleAndIsbn = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( all( contains(title, "Hibernate"), equal( isbn, "9781932394153" ) ) ) + .toQuery( session ) .getResultList() ); assertEquals( 1, booksByTitleAndIsbn.size() ); List booksByTitleOrIsbn = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( any( contains(title, "Hibernate"), equal( isbn, "9781932394153" ) ) ) + .toQuery( session ) .getResultList() ); assertEquals( 2, booksByTitleOrIsbn.size() ); List booksByIsbn1 = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( in( isbn, "9781932394153", "9781617290459", "XYZ" ) ) + .toQuery( session ) .getResultList() ); assertEquals( 2, booksByIsbn1.size() ); List booksByIsbn2 = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( in( isbn, List.of("9781617290459", "XYZ", "ABC") ) ) + .toQuery( session ) .getResultList() ); assertEquals( 1, booksByIsbn2.size() ); } @@ -174,44 +190,51 @@ void testPath(SessionFactoryScope scope) { var version = (SingularAttribute) pubType.findSingularAttribute("version"); scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( from(Book.class).equalTo( session.find(Book.class, "9781932394153") ) ) + .toQuery( session ) .getSingleResult() ); List booksInIsbn = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( from(Book.class).to(isbn).in( List.of("9781932394153", "9781617290459") ) ) .setOrder( desc( isbn ) ) + .toQuery( session ) .getResultList() ); assertEquals( 2, booksInIsbn.size() ); List booksWithPub = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( from(Book.class).to(publisher).to(name).equalTo("Manning") ) .setOrder( desc( title ) ) + .toQuery( session ) .getResultList() ); assertEquals( 2, booksWithPub.size() ); List noBookWithPub = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( from(Book.class).to(publisher).to(name).notEqualTo("Manning") ) .setOrder( desc( title ) ) + .toQuery( session ) .getResultList() ); assertEquals( 0, noBookWithPub.size() ); List books = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( from(Book.class).to(title).restrict( containing("hibernate", false) ) ) .setOrder( desc( title ) ) + .toQuery( session ) .getResultList() ); assertEquals( 2, books.size() ); List booksWithPubVersion = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( from(Book.class).to(publisher).to(version).restrict( greaterThan(5) ) ) + .toQuery( session ) .getResultList() ); assertEquals( 0, booksWithPubVersion.size() ); List unsafeTest = scope.fromSession( session -> - session.createSelectionQuery( "from Book", Book.class) + session.createSelectionCriteria( "from Book", Book.class) .addRestriction( from(Book.class) .to("publisher", Publisher.class) .to("name", String.class).equalTo("Manning") ) + .toQuery( session ) .getResultList() ); assertEquals( 2, unsafeTest.size() ); } From 0292679ee075e8b01cda31ef8792f15adc01f8be Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 15 Apr 2025 18:51:38 +0200 Subject: [PATCH 2/4] Remove addRestriction and setOrder APIs from SelectionQuery --- .../procedure/internal/ProcedureCallImpl.java | 11 ------ .../main/java/org/hibernate/query/Query.java | 10 ----- .../org/hibernate/query/QueryProducer.java | 1 + .../org/hibernate/query/SelectionQuery.java | 39 ------------------- .../hibernate/query/spi/AbstractQuery.java | 19 --------- .../query/sql/internal/NativeQueryImpl.java | 17 -------- .../internal/AbstractSqmSelectionQuery.java | 38 ------------------ .../query/sqm/internal/QuerySqmImpl.java | 20 ---------- ...elegatingSqmSelectionQueryImplementor.java | 22 ----------- 9 files changed, 1 insertion(+), 176 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java index 2264fb09ca5a..30f2072285e3 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java @@ -44,7 +44,6 @@ import org.hibernate.query.BindableType; import org.hibernate.query.KeyedPage; import org.hibernate.query.KeyedResultList; -import org.hibernate.query.Order; import org.hibernate.query.OutputableType; import org.hibernate.query.Query; import org.hibernate.query.QueryParameter; @@ -411,16 +410,6 @@ public QueryParameterBindings getParameterBindings() { return parameterBindings; } - @Override - public Query setOrder(List> orderList) { - throw new UnsupportedOperationException("Ordering not supported for stored procedure calls"); - } - - @Override - public Query setOrder(Order order) { - throw new UnsupportedOperationException("Ordering not supported for stored procedure calls"); - } - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Parameter registrations 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 4d705a96fddb..e45386c9feb1 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/Query.java +++ b/hibernate-core/src/main/java/org/hibernate/query/Query.java @@ -26,7 +26,6 @@ import org.hibernate.dialect.Dialect; import org.hibernate.graph.GraphSemantic; import org.hibernate.graph.RootGraph; -import org.hibernate.query.restriction.Restriction; import org.hibernate.query.spi.QueryOptions; import org.hibernate.transform.ResultTransformer; @@ -929,15 +928,6 @@ default Query setPage(Page page) { @Override Query setLockMode(LockModeType lockMode); - @Override @Incubating - Query setOrder(List> orderList); - - @Override @Incubating - Query setOrder(Order order); - - @Override @Incubating - Query addRestriction(Restriction restriction); - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // deprecated methods diff --git a/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java b/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java index 91c0fd3216ae..da48d85412fe 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java +++ b/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java @@ -5,6 +5,7 @@ package org.hibernate.query; import jakarta.persistence.EntityGraph; +import org.hibernate.Incubating; import org.hibernate.query.criteria.JpaCriteriaInsert; import jakarta.persistence.TypedQueryReference; 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 f40b5f72e18f..cebd4a1d9d2c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/SelectionQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/SelectionQuery.java @@ -603,45 +603,6 @@ default Stream stream() { */ SelectionQuery setLockMode(String alias, LockMode lockMode); - /** - * If the result type of this query is an entity class, add one or more - * {@linkplain Order rules} for ordering the query results. - * - * @param orderList one or more instances of {@link Order} - * - * @see Order - * - * @since 6.3 - */ - @Incubating - SelectionQuery setOrder(List> orderList); - - /** - * If the result type of this query is an entity class, add a - * {@linkplain Order rule} for ordering the query results. - * - * @param order an instance of {@link Order} - * - * @see Order - * - * @since 6.3 - */ - @Incubating - SelectionQuery setOrder(Order order); - - /** - * If the result type of this query is an entity class, add a - * {@linkplain Restriction rule} for restricting the query results. - * - * @param restriction an instance of {@link Restriction} - * - * @see Restriction - * - * @since 7.0 - */ - @Incubating - SelectionQuery addRestriction(Restriction restriction); - /** * Specifies whether follow-on locking should be applied */ 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 67a5edf9863e..09b8b2b7fb64 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 @@ -9,7 +9,6 @@ import java.util.Collection; import java.util.Date; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; @@ -36,10 +35,7 @@ import org.hibernate.query.IllegalQueryOperationException; import org.hibernate.query.KeyedPage; import org.hibernate.query.KeyedResultList; -import org.hibernate.query.Order; -import org.hibernate.query.Query; import org.hibernate.query.QueryParameter; -import org.hibernate.query.restriction.Restriction; import org.hibernate.query.ResultListTransformer; import org.hibernate.query.TupleTransformer; import org.hibernate.query.named.NamedQueryMemento; @@ -291,21 +287,6 @@ public QueryImplementor setLockMode(LockModeType lockModeType) { return this; } - @Override - public Query setOrder(List> orders) { - throw new UnsupportedOperationException( "Should be implemented by " + this.getClass().getName() ); - } - - @Override - public Query setOrder(Order order) { - throw new UnsupportedOperationException( "Should be implemented by " + this.getClass().getName() ); - } - - @Override - public Query addRestriction(Restriction restriction) { - throw new UnsupportedOperationException( "Should be implemented by " + this.getClass().getName() ); - } - @Override public String getComment() { return super.getComment(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java index ccacf69f192f..25d6145e1e6d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java @@ -51,11 +51,9 @@ import org.hibernate.query.KeyedPage; import org.hibernate.query.KeyedResultList; import org.hibernate.query.NativeQuery; -import org.hibernate.query.Order; import org.hibernate.query.PathException; import org.hibernate.query.Query; import org.hibernate.query.QueryParameter; -import org.hibernate.query.restriction.Restriction; import org.hibernate.query.ResultListTransformer; import org.hibernate.query.TupleTransformer; import org.hibernate.query.internal.DelegatingDomainQueryExecutionContext; @@ -1652,21 +1650,6 @@ public NativeQueryImplementor setFirstResult(int startPosition) { return this; } - @Override - public Query setOrder(List> orderList) { - throw new UnsupportedOperationException("Ordering not currently supported for native queries"); - } - - @Override - public Query setOrder(Order order) { - throw new UnsupportedOperationException("Ordering not currently supported for native queries"); - } - - @Override - public Query addRestriction(Restriction restriction) { - throw new UnsupportedOperationException("Restrictions not currently supported for native queries"); - } - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Hints diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AbstractSqmSelectionQuery.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AbstractSqmSelectionQuery.java index e5db42eb6ba3..5d5294bf588d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AbstractSqmSelectionQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AbstractSqmSelectionQuery.java @@ -10,10 +10,8 @@ import org.hibernate.query.IllegalSelectQueryException; import org.hibernate.query.KeyedPage; import org.hibernate.query.KeyedResultList; -import org.hibernate.query.Order; import org.hibernate.query.Page; import org.hibernate.query.QueryLogging; -import org.hibernate.query.restriction.Restriction; import org.hibernate.query.SelectionQuery; import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.hql.internal.QuerySplitter; @@ -41,14 +39,12 @@ import jakarta.persistence.TupleElement; import jakarta.persistence.criteria.CompoundSelection; -import static java.util.stream.Collectors.toList; import static org.hibernate.cfg.QuerySettings.FAIL_ON_PAGINATION_OVER_COLLECTION_FETCH; import static org.hibernate.query.KeyedPage.KeyInterpretation.KEY_OF_FIRST_ON_NEXT_PAGE; import static org.hibernate.query.sqm.internal.KeyedResult.collectKeys; import static org.hibernate.query.sqm.internal.KeyedResult.collectResults; import static org.hibernate.query.sqm.internal.SqmUtil.isHqlTuple; import static org.hibernate.query.sqm.internal.SqmUtil.isSelectionAssignableToResultType; -import static org.hibernate.query.sqm.internal.SqmUtil.sortSpecification; import static org.hibernate.query.sqm.tree.SqmCopyContext.noParamCopyContext; /** @@ -118,40 +114,6 @@ private SqmSelectStatement getSqmSelectStatement() { } } - @Override - public SelectionQuery setOrder(List> orderList) { - final SqmSelectStatement selectStatement = getSqmSelectStatement().copy( noParamCopyContext() ); - selectStatement.orderBy( orderList.stream().map( order -> sortSpecification( selectStatement, order ) ) - .collect( toList() ) ); - // TODO: when the QueryInterpretationCache can handle caching criteria queries, - // simply cache the new SQM as if it were a criteria query, and remove this: - getQueryOptions().setQueryPlanCachingEnabled( false ); - setSqmStatement( selectStatement ); - return this; - } - - - @Override - public SelectionQuery setOrder(Order order) { - final SqmSelectStatement selectStatement = getSqmSelectStatement().copy( noParamCopyContext() ); - selectStatement.orderBy( sortSpecification( selectStatement, order ) ); - // TODO: when the QueryInterpretationCache can handle caching criteria queries, - // simply cache the new SQM as if it were a criteria query, and remove this: - getQueryOptions().setQueryPlanCachingEnabled( false ); - setSqmStatement( selectStatement ); - return this; - } - - @Override - public SelectionQuery addRestriction(Restriction restriction) { - final SqmSelectStatement selectStatement = getSqmSelectStatement().copy( noParamCopyContext() ); - restriction.apply( selectStatement, selectStatement.getRoot( 0, getExpectedResultType() ) ); - // TODO: when the QueryInterpretationCache can handle caching criteria queries, - // simply cache the new SQM as if it were a criteria query, and remove this: - getQueryOptions().setQueryPlanCachingEnabled( false ); - setSqmStatement( selectStatement ); - return this; - } @Override public SelectionQuery setPage(Page page) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java index 2b745cbfe339..7e3392c05471 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java @@ -38,11 +38,9 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.query.BindableType; import org.hibernate.query.IllegalQueryOperationException; -import org.hibernate.query.Order; import org.hibernate.query.Page; import org.hibernate.query.Query; import org.hibernate.query.QueryParameter; -import org.hibernate.query.restriction.Restriction; import org.hibernate.query.ResultListTransformer; import org.hibernate.query.TupleTransformer; import org.hibernate.query.criteria.internal.NamedCriteriaQueryMementoImpl; @@ -768,24 +766,6 @@ public LockModeType getLockMode() { return getLockOptions().getLockMode().toJpaLockMode(); } - @Override - public Query setOrder(Order order) { - super.setOrder(order); - return this; - } - - @Override - public Query addRestriction(Restriction restriction) { - super.addRestriction( restriction ); - return this; - } - - @Override - public Query setOrder(List> orders) { - super.setOrder(orders); - return this; - } - @Override public Query setPage(Page page) { super.setPage(page); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/DelegatingSqmSelectionQueryImplementor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/DelegatingSqmSelectionQueryImplementor.java index 3e98330a685f..1c706d3413ee 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/DelegatingSqmSelectionQueryImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/DelegatingSqmSelectionQueryImplementor.java @@ -24,14 +24,12 @@ import org.hibernate.query.BindableType; import org.hibernate.query.KeyedPage; import org.hibernate.query.KeyedResultList; -import org.hibernate.query.Order; import org.hibernate.query.Page; import org.hibernate.query.ParameterMetadata; import org.hibernate.query.QueryFlushMode; import org.hibernate.query.QueryParameter; import org.hibernate.query.ResultListTransformer; import org.hibernate.query.TupleTransformer; -import org.hibernate.query.restriction.Restriction; import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.sqm.SqmSelectionQuery; import org.hibernate.query.sqm.tree.SqmStatement; @@ -296,26 +294,6 @@ public SqmSelectionQueryImplementor setLockMode(String alias, LockMode lockMo return this; } - @Override - @Incubating - public SqmSelectionQueryImplementor setOrder(List> orders) { - getDelegate().setOrder( orders ); - return this; - } - - @Override - @Incubating - public SqmSelectionQueryImplementor setOrder(Order order) { - getDelegate().setOrder( order ); - return this; - } - - @Override - public SqmSelectionQueryImplementor addRestriction(Restriction restriction) { - getDelegate().addRestriction( restriction ); - return this; - } - @Override public SqmSelectionQueryImplementor setFollowOnLocking(boolean enable) { getDelegate().setFollowOnLocking( enable ); From 572c91cf9936856fc2c1ccd13bb12545654c7ce1 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 15 Apr 2025 19:22:37 +0200 Subject: [PATCH 3/4] Change annotation processor to use JPA Criteria extension instead of mutating Query --- .../internal/AbstractSqmSelectionQuery.java | 1 - .../annotation/AbstractCriteriaMethod.java | 28 +++++++++ .../annotation/AbstractQueryMethod.java | 17 ++++++ .../annotation/CriteriaFinderMethod.java | 14 +++-- .../processor/annotation/QueryMethod.java | 58 +++++++++++++++++-- .../hibernate/processor/util/Constants.java | 2 + 6 files changed, 111 insertions(+), 9 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AbstractSqmSelectionQuery.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AbstractSqmSelectionQuery.java index 5d5294bf588d..2332d6a1939a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AbstractSqmSelectionQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/AbstractSqmSelectionQuery.java @@ -45,7 +45,6 @@ import static org.hibernate.query.sqm.internal.KeyedResult.collectResults; import static org.hibernate.query.sqm.internal.SqmUtil.isHqlTuple; import static org.hibernate.query.sqm.internal.SqmUtil.isSelectionAssignableToResultType; -import static org.hibernate.query.sqm.tree.SqmCopyContext.noParamCopyContext; /** * @author Gavin King diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractCriteriaMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractCriteriaMethod.java index cd33def591f1..85bc31235ce5 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractCriteriaMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractCriteriaMethod.java @@ -11,6 +11,8 @@ import java.util.List; import java.util.StringTokenizer; +import static org.hibernate.processor.util.Constants.HIB_JPA_CRITERIA_QUERY; +import static org.hibernate.processor.util.Constants.HIB_SHARED_SESSION; import static org.hibernate.processor.util.TypeUtils.getGeneratedClassFullyQualifiedName; import static org.hibernate.processor.util.TypeUtils.isPrimitive; @@ -83,6 +85,32 @@ void createQuery(StringBuilder declaration) { .append("(_query)\n"); } + void createQuery(StringBuilder declaration, List paramTypes, @Nullable String containerType) { + var hasOrdering = hasOrderParameters( containerType, paramTypes ); + var hasRestrictions = hasRestrictionParameters( paramTypes ); + + if ( hasOrdering || hasRestrictions ) { + declaration.append( "((" ).append( annotationMetaEntity.importType(HIB_JPA_CRITERIA_QUERY) ).append( "<" ); + declaration.append( annotationMetaEntity.importType(entity) ).append( ">) _query)\n" ); + if ( hasOrdering ) { + applyOrder( declaration, paramTypes, containerType, true ); + } + if ( hasRestrictions ) { + handleRestrictionParameters( declaration, paramTypes ); + } + declaration.append("\t\t\t.toQuery(").append( localSessionName() ); + if ( isUsingEntityManager() ) { + declaration.append( ".unwrap(" ) + .append( annotationMetaEntity.importType( HIB_SHARED_SESSION ) ) + .append( ".class)\n" ); + } + declaration.append( ")\n"); + } + else { + createQuery( declaration ); + } + } + void createCriteriaQuery(StringBuilder declaration) { final String entityClass = annotationMetaEntity.importType(entity); declaration diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractQueryMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractQueryMethod.java index 7c42ea1ea71b..02d98159ba43 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractQueryMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractQueryMethod.java @@ -264,6 +264,10 @@ else if ( jakartaPageRequest ) { } } + boolean hasOrderParameters(@Nullable String containerType, List paramTypes) { + return !isJakartaCursoredPage(containerType) && hasOrdering(paramTypes); + } + boolean applyOrder( StringBuilder declaration, List paramTypes, @Nullable String containerType, boolean unwrapped) { @@ -290,6 +294,19 @@ void handlePageParameters( } } + boolean hasRestrictionParameters(List paramTypes) { + for ( int i = 0; i < paramNames.size(); i++ ) { + final String paramType = paramTypes.get( i ); + if ( isRestrictionParam( paramType ) ) { + return true; + } + else if ( isRangeParam( paramType ) && returnTypeName != null ) { + return true; + } + } + return false; + } + void handleRestrictionParameters( StringBuilder declaration, List paramTypes) { for ( int i = 0; i < paramNames.size(); i ++ ) { diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaFinderMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaFinderMethod.java index a342146f05bf..40457bedbfc7 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaFinderMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaFinderMethod.java @@ -57,12 +57,18 @@ void executeQuery(StringBuilder declaration, List paramTypes) { collectOrdering( declaration, paramTypes ); tryReturn( declaration, paramTypes, containerType ); castResult( declaration ); - createQuery( declaration ); - handleRestrictionParameters( declaration, paramTypes ); - handlePageParameters( declaration, paramTypes, containerType ); boolean unwrapped = !isUsingEntityManager(); + if ( isReactive() ) { + // Reactive doesn't support the createSelectionCriteria() method yet + createQuery( declaration ); + handleRestrictionParameters( declaration, paramTypes ); + unwrapped = applyOrder( declaration, paramTypes, containerType, unwrapped ); + } + else { + createQuery( declaration, paramTypes, containerType ); + } + handlePageParameters( declaration, paramTypes, containerType ); unwrapped = enableFetchProfile( declaration, unwrapped ); - unwrapped = applyOrder( declaration, paramTypes, containerType, unwrapped ); execute( declaration, paramTypes, unwrapped ); } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/QueryMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/QueryMethod.java index dc5c7b8c22a3..a324d3e9e3d7 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/QueryMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/QueryMethod.java @@ -11,6 +11,7 @@ import java.util.List; import static org.hibernate.processor.util.Constants.BOOLEAN; +import static org.hibernate.processor.util.Constants.HIB_SHARED_SESSION; import static org.hibernate.processor.util.Constants.QUERY; import static org.hibernate.processor.util.Constants.VOID; import static org.hibernate.processor.util.StringUtil.getUpperUnderscoreCaseFromLowerCamelCase; @@ -96,12 +97,18 @@ public String getAttributeDeclarationString() { chainSession( declaration ); tryReturn( declaration, paramTypes, containerType ); castResult( declaration ); - createQuery( declaration ); - handleRestrictionParameters( declaration, paramTypes ); + boolean unwrapped = !isUsingEntityManager(); + if ( isReactive() ) { + // Reactive doesn't support the createSelectionCriteria() method yet + createQuery( declaration ); + handleRestrictionParameters( declaration, paramTypes ); + unwrapped = applyOrder( declaration, paramTypes, containerType, unwrapped ); + } + else { + createQuery( declaration, paramTypes, containerType ); + } setParameters( declaration, paramTypes, ""); handlePageParameters( declaration, paramTypes, containerType ); - boolean unwrapped = !isUsingEntityManager(); - unwrapped = applyOrder( declaration, paramTypes, containerType, unwrapped ); execute( declaration, unwrapped ); convertExceptions( declaration ); chainSessionEnd( isUpdate, declaration ); @@ -126,6 +133,49 @@ void createQuery(StringBuilder declaration) { declaration.append(")\n"); } + void createQuery(StringBuilder declaration, List paramTypes, @Nullable String containerType) { + var hasOrdering = hasOrderParameters( containerType, paramTypes ); + var hasRestrictions = hasRestrictionParameters( paramTypes ); + + declaration.append(localSessionName()); + + if ( hasOrdering || hasRestrictions ) { + if ( isUsingEntityManager() ) { + declaration.append( ".unwrap(" ) + .append( annotationMetaEntity.importType( HIB_SHARED_SESSION ) ) + .append( ".class)\n" ); + } + declaration.append("\t\t\t.createSelectionCriteria"); + } + else { + declaration.append( '.' ).append( createQueryMethod() ); + } + declaration.append("(") + .append(getConstantName()); + if ( returnTypeClass != null && !isUpdate ) { + declaration + .append(", ") + .append(annotationMetaEntity.importType(returnTypeClass)) + .append(".class"); + } + declaration.append(")\n"); + if ( hasOrdering || hasRestrictions ) { + if ( hasOrdering ) { + applyOrder( declaration, paramTypes, containerType, true ); + } + if ( hasRestrictions ) { + handleRestrictionParameters( declaration, paramTypes ); + } + declaration.append("\t\t\t.toQuery(").append( localSessionName() ); + if ( isUsingEntityManager() ) { + declaration.append( ".unwrap(" ) + .append( annotationMetaEntity.importType( HIB_SHARED_SESSION ) ) + .append( ".class)\n" ); + } + declaration.append( ")\n"); + } + } + private String createQueryMethod() { if ( isNative ) { return "createNativeQuery"; diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/Constants.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/Constants.java index 37eaf2763a9b..cbc96bfe178a 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/Constants.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/Constants.java @@ -103,6 +103,8 @@ public final class Constants { public static final String HIB_QUERY = "org.hibernate.query.Query"; public static final String HIB_SELECTION_QUERY = "org.hibernate.query.SelectionQuery"; public static final String HIB_SESSION = "org.hibernate.Session"; + public static final String HIB_SHARED_SESSION = "org.hibernate.SharedSessionContract"; + public static final String HIB_JPA_CRITERIA_QUERY = "org.hibernate.query.criteria.JpaCriteriaQuery"; public static final String HIB_SESSION_FACTORY = "org.hibernate.SessionFactory"; public static final String HIB_STATELESS_SESSION = "org.hibernate.StatelessSession"; public static final String MUTINY_SESSION_FACTORY = "org.hibernate.reactive.mutiny.Mutiny.SessionFactory"; From 2c034482ed1992e9e116b39855df40b2134f3408 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 15 Apr 2025 20:10:40 +0200 Subject: [PATCH 4/4] Add SelectionBuilder interface as more targeted option for applying Order and Restriction to a base query --- .../engine/spi/SessionDelegatorBaseImpl.java | 6 ++ .../engine/spi/SessionLazyDelegator.java | 6 ++ .../spi/SharedSessionDelegatorBaseImpl.java | 6 ++ .../AbstractSharedSessionContract.java | 7 ++ .../org/hibernate/query/QueryProducer.java | 13 ++++ .../org/hibernate/query/SelectionBuilder.java | 65 +++++++++++++++++++ .../query/criteria/JpaCriteriaQuery.java | 4 +- .../query/internal/SelectionBuilderImpl.java | 48 ++++++++++++++ .../annotation/AbstractCriteriaMethod.java | 15 ++--- .../annotation/CriteriaFinderMethod.java | 12 +--- .../processor/annotation/QueryMethod.java | 4 +- 11 files changed, 164 insertions(+), 22 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/query/SelectionBuilder.java create mode 100644 hibernate-core/src/main/java/org/hibernate/query/internal/SelectionBuilderImpl.java diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java index 1abff79c1de7..fad17e145436 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java @@ -46,6 +46,7 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.procedure.ProcedureCall; import org.hibernate.query.MutationQuery; +import org.hibernate.query.SelectionBuilder; import org.hibernate.query.SelectionQuery; import org.hibernate.query.criteria.HibernateCriteriaBuilder; import org.hibernate.query.criteria.JpaCriteriaInsert; @@ -593,6 +594,11 @@ public JpaCriteriaQuery createSelectionCriteria(String hqlString, Class SelectionBuilder createSelectionBuilder(String hqlString, Class resultClass) { + return queryDelegate().createSelectionBuilder( hqlString, resultClass ); + } + @Override public SelectionQuery createSelectionQuery(CriteriaQuery criteria) { return queryDelegate().createSelectionQuery( criteria ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java index 5df52240c896..addc6ebef8f1 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java @@ -38,6 +38,7 @@ import org.hibernate.query.MutationQuery; import org.hibernate.query.NativeQuery; import org.hibernate.query.Query; +import org.hibernate.query.SelectionBuilder; import org.hibernate.query.SelectionQuery; import org.hibernate.query.criteria.HibernateCriteriaBuilder; import org.hibernate.query.criteria.JpaCriteriaInsert; @@ -710,6 +711,11 @@ public JpaCriteriaQuery createSelectionCriteria(String hqlString, Class SelectionBuilder createSelectionBuilder(String hqlString, Class resultClass) { + return this.lazySession.get().createSelectionBuilder( hqlString, resultClass ); + } + @Override public SelectionQuery createSelectionQuery(CriteriaQuery criteria) { return this.lazySession.get().createSelectionQuery( criteria ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java index 890c7a435e2e..0f2420fdf65f 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java @@ -34,6 +34,7 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.procedure.ProcedureCall; import org.hibernate.query.MutationQuery; +import org.hibernate.query.SelectionBuilder; import org.hibernate.query.SelectionQuery; import org.hibernate.query.criteria.HibernateCriteriaBuilder; import org.hibernate.query.criteria.JpaCriteriaInsert; @@ -160,6 +161,11 @@ public JpaCriteriaQuery createSelectionCriteria(String hqlString, Class SelectionBuilder createSelectionBuilder(String hqlString, Class resultClass) { + return queryDelegate().createSelectionBuilder( hqlString, resultClass ); + } + @Override public SelectionQuery createSelectionQuery(CriteriaQuery criteria) { return queryDelegate().createSelectionQuery( criteria ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index d6c6ee48dc97..c5cd7685fd5d 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -70,6 +70,7 @@ import org.hibernate.query.MutationQuery; import org.hibernate.query.Query; import org.hibernate.query.QueryTypeMismatchException; +import org.hibernate.query.SelectionBuilder; import org.hibernate.query.SelectionQuery; import org.hibernate.query.UnknownNamedQueryException; import org.hibernate.query.criteria.CriteriaDefinition; @@ -77,6 +78,7 @@ import org.hibernate.query.criteria.JpaCriteriaInsert; import org.hibernate.query.criteria.JpaCriteriaQuery; import org.hibernate.query.hql.spi.SqmQueryImplementor; +import org.hibernate.query.internal.SelectionBuilderImpl; import org.hibernate.query.named.NamedObjectRepository; import org.hibernate.query.named.NamedResultSetMappingMemento; import org.hibernate.query.spi.HqlInterpretation; @@ -877,6 +879,11 @@ public JpaCriteriaQuery createSelectionCriteria(String hqlString, Class SelectionBuilder createSelectionBuilder(String hqlString, Class resultClass) { + return new SelectionBuilderImpl<>( getCriteriaBuilder().createQuery(hqlString, resultClass), this ); + } + @Override public SelectionQuery createSelectionQuery(CriteriaQuery criteria) { if ( criteria instanceof CriteriaDefinition criteriaDefinition ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java b/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java index da48d85412fe..162b9bb8a231 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java +++ b/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java @@ -392,6 +392,19 @@ public interface QueryProducer { @Incubating JpaCriteriaQuery createSelectionCriteria(String hqlString, Class resultClass); + /** + * Transform the given HQL {@code select} query to an equivalent criteria query. + * + * @param hqlString The HQL {@code select} query + * @param resultClass The result type of the query + * + * @see org.hibernate.query.criteria.HibernateCriteriaBuilder#createQuery(String, Class) + * + * @since 7.0 + */ + @Incubating + SelectionBuilder createSelectionBuilder(String hqlString, Class resultClass); + /** * Create a {@link SelectionQuery} reference for the given * {@link CriteriaQuery}. diff --git a/hibernate-core/src/main/java/org/hibernate/query/SelectionBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/SelectionBuilder.java new file mode 100644 index 000000000000..70eea3697676 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/SelectionBuilder.java @@ -0,0 +1,65 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.query; + +import org.hibernate.Incubating; +import org.hibernate.query.restriction.Restriction; + +import java.util.List; + +/** + * A builder for a {@link SelectionQuery}. + * + * @since 7.0 + */ +@Incubating +public interface SelectionBuilder { + + /** + * If the result type of this query is an entity class, add one or more + * {@linkplain org.hibernate.query.Order rules} for ordering the query results. + * + * @param orderList one or more instances of {@link org.hibernate.query.Order} + * + * @see org.hibernate.query.Order + * + * @since 7.0 + */ + @Incubating + SelectionBuilder setOrder(List> orderList); + + /** + * If the result type of this query is an entity class, add a + * {@linkplain org.hibernate.query.Order rule} for ordering the query results. + * + * @param order an instance of {@link org.hibernate.query.Order} + * + * @see org.hibernate.query.Order + * + * @since 7.0 + */ + @Incubating + SelectionBuilder setOrder(org.hibernate.query.Order order); + + /** + * If the result type of this query is an entity class, add a + * {@linkplain Restriction rule} for restricting the query results. + * + * @param restriction an instance of {@link Restriction} + * + * @see Restriction + * + * @since 7.0 + */ + @Incubating + SelectionBuilder addRestriction(Restriction restriction); + + /** + * Creates a query for this selection builder. + * + * @since 7.0 + */ + SelectionQuery createQuery(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaCriteriaQuery.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaCriteriaQuery.java index bc26477a80e6..ac6bf3e5e97f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaCriteriaQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaCriteriaQuery.java @@ -9,7 +9,7 @@ import org.hibernate.Incubating; import org.hibernate.SharedSessionContract; -import org.hibernate.query.Query; +import org.hibernate.query.SelectionQuery; import org.hibernate.query.common.FetchClauseType; import jakarta.persistence.criteria.CriteriaQuery; @@ -87,7 +87,7 @@ public interface JpaCriteriaQuery extends CriteriaQuery, JpaQueryableCrite * @since 7.0 */ @Incubating - default Query toQuery(SharedSessionContract session) { + default SelectionQuery toQuery(SharedSessionContract session) { return session.createQuery( this ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/SelectionBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/SelectionBuilderImpl.java new file mode 100644 index 000000000000..037a3f5166df --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/SelectionBuilderImpl.java @@ -0,0 +1,48 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.query.internal; + +import org.hibernate.SharedSessionContract; +import org.hibernate.query.Order; +import org.hibernate.query.SelectionBuilder; +import org.hibernate.query.SelectionQuery; +import org.hibernate.query.criteria.JpaCriteriaQuery; +import org.hibernate.query.restriction.Restriction; + +import java.util.List; + +public class SelectionBuilderImpl implements SelectionBuilder { + + private final JpaCriteriaQuery query; + private final SharedSessionContract session; + + public SelectionBuilderImpl(JpaCriteriaQuery query, SharedSessionContract session) { + this.query = query; + this.session = session; + } + + @Override + public SelectionBuilder setOrder(List> orderList) { + query.setOrder( orderList ); + return this; + } + + @Override + public SelectionBuilder setOrder(Order order) { + query.setOrder( order ); + return this; + } + + @Override + public SelectionBuilder addRestriction(Restriction restriction) { + query.addRestriction( restriction ); + return this; + } + + @Override + public SelectionQuery createQuery() { + return session.createQuery( query ); + } +} diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractCriteriaMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractCriteriaMethod.java index 85bc31235ce5..7f99c8c4fe7c 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractCriteriaMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractCriteriaMethod.java @@ -12,7 +12,6 @@ import java.util.StringTokenizer; import static org.hibernate.processor.util.Constants.HIB_JPA_CRITERIA_QUERY; -import static org.hibernate.processor.util.Constants.HIB_SHARED_SESSION; import static org.hibernate.processor.util.TypeUtils.getGeneratedClassFullyQualifiedName; import static org.hibernate.processor.util.TypeUtils.isPrimitive; @@ -90,6 +89,12 @@ void createQuery(StringBuilder declaration, List paramTypes, @Nullable S var hasRestrictions = hasRestrictionParameters( paramTypes ); if ( hasOrdering || hasRestrictions ) { + declaration + .append(localSessionName()) + .append(".") + .append(createQueryMethod()) + .append("("); + declaration.append( "((" ).append( annotationMetaEntity.importType(HIB_JPA_CRITERIA_QUERY) ).append( "<" ); declaration.append( annotationMetaEntity.importType(entity) ).append( ">) _query)\n" ); if ( hasOrdering ) { @@ -98,13 +103,7 @@ void createQuery(StringBuilder declaration, List paramTypes, @Nullable S if ( hasRestrictions ) { handleRestrictionParameters( declaration, paramTypes ); } - declaration.append("\t\t\t.toQuery(").append( localSessionName() ); - if ( isUsingEntityManager() ) { - declaration.append( ".unwrap(" ) - .append( annotationMetaEntity.importType( HIB_SHARED_SESSION ) ) - .append( ".class)\n" ); - } - declaration.append( ")\n"); + declaration.append( "))\n"); } else { createQuery( declaration ); diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaFinderMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaFinderMethod.java index 40457bedbfc7..f0180eb6f063 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaFinderMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaFinderMethod.java @@ -57,17 +57,9 @@ void executeQuery(StringBuilder declaration, List paramTypes) { collectOrdering( declaration, paramTypes ); tryReturn( declaration, paramTypes, containerType ); castResult( declaration ); - boolean unwrapped = !isUsingEntityManager(); - if ( isReactive() ) { - // Reactive doesn't support the createSelectionCriteria() method yet - createQuery( declaration ); - handleRestrictionParameters( declaration, paramTypes ); - unwrapped = applyOrder( declaration, paramTypes, containerType, unwrapped ); - } - else { - createQuery( declaration, paramTypes, containerType ); - } + createQuery( declaration, paramTypes, containerType ); handlePageParameters( declaration, paramTypes, containerType ); + boolean unwrapped = !isUsingEntityManager(); unwrapped = enableFetchProfile( declaration, unwrapped ); execute( declaration, paramTypes, unwrapped ); } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/QueryMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/QueryMethod.java index a324d3e9e3d7..832493245238 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/QueryMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/QueryMethod.java @@ -99,7 +99,7 @@ public String getAttributeDeclarationString() { castResult( declaration ); boolean unwrapped = !isUsingEntityManager(); if ( isReactive() ) { - // Reactive doesn't support the createSelectionCriteria() method yet + // Reactive doesn't support the createSelectionBuilder() method yet createQuery( declaration ); handleRestrictionParameters( declaration, paramTypes ); unwrapped = applyOrder( declaration, paramTypes, containerType, unwrapped ); @@ -145,7 +145,7 @@ void createQuery(StringBuilder declaration, List paramTypes, @Nullable S .append( annotationMetaEntity.importType( HIB_SHARED_SESSION ) ) .append( ".class)\n" ); } - declaration.append("\t\t\t.createSelectionCriteria"); + declaration.append("\t\t\t.createSelectionBuilder"); } else { declaration.append( '.' ).append( createQueryMethod() );