Skip to content

Commit 20c2288

Browse files
committed
Add JPA Criteria API extension for adding Restriction, Order and allow fluent construction of Query from CriteriaQuery
1 parent 0122a5a commit 20c2288

File tree

12 files changed

+283
-84
lines changed

12 files changed

+283
-84
lines changed

hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import org.hibernate.query.SelectionQuery;
5050
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
5151
import org.hibernate.query.criteria.JpaCriteriaInsert;
52+
import org.hibernate.query.criteria.JpaCriteriaQuery;
5253
import org.hibernate.query.spi.QueryImplementor;
5354
import org.hibernate.query.spi.QueryProducerImplementor;
5455
import org.hibernate.query.sql.spi.NativeQueryImplementor;
@@ -587,6 +588,11 @@ public <R> SelectionQuery<R> createSelectionQuery(String hqlString, EntityGraph<
587588
return queryDelegate().createSelectionQuery( hqlString, resultGraph );
588589
}
589590

591+
@Override
592+
public <R> JpaCriteriaQuery<R> createSelectionCriteria(String hqlString, Class<R> resultClass) {
593+
return queryDelegate().createSelectionCriteria( hqlString, resultClass );
594+
}
595+
590596
@Override
591597
public <R> SelectionQuery<R> createSelectionQuery(CriteriaQuery<R> criteria) {
592598
return queryDelegate().createSelectionQuery( criteria );

hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.hibernate.query.SelectionQuery;
4242
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
4343
import org.hibernate.query.criteria.JpaCriteriaInsert;
44+
import org.hibernate.query.criteria.JpaCriteriaQuery;
4445
import org.hibernate.stat.SessionStatistics;
4546

4647
import jakarta.persistence.ConnectionConsumer;
@@ -704,6 +705,11 @@ public <R> SelectionQuery<R> createSelectionQuery(String hqlString, EntityGraph<
704705
return this.lazySession.get().createSelectionQuery( hqlString, resultGraph );
705706
}
706707

708+
@Override
709+
public <R> JpaCriteriaQuery<R> createSelectionCriteria(String hqlString, Class<R> resultClass) {
710+
return this.lazySession.get().createSelectionCriteria( hqlString, resultClass );
711+
}
712+
707713
@Override
708714
public <R> SelectionQuery<R> createSelectionQuery(CriteriaQuery<R> criteria) {
709715
return this.lazySession.get().createSelectionQuery( criteria );

hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.hibernate.query.SelectionQuery;
3838
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
3939
import org.hibernate.query.criteria.JpaCriteriaInsert;
40+
import org.hibernate.query.criteria.JpaCriteriaQuery;
4041
import org.hibernate.query.spi.QueryImplementor;
4142
import org.hibernate.query.spi.QueryProducerImplementor;
4243
import org.hibernate.query.sql.spi.NativeQueryImplementor;
@@ -154,6 +155,11 @@ public <R> SelectionQuery<R> createSelectionQuery(String hqlString, EntityGraph<
154155
return queryDelegate().createSelectionQuery( hqlString, resultGraph );
155156
}
156157

158+
@Override
159+
public <R> JpaCriteriaQuery<R> createSelectionCriteria(String hqlString, Class<R> resultClass) {
160+
return queryDelegate().createSelectionCriteria( hqlString, resultClass );
161+
}
162+
157163
@Override
158164
public <R> SelectionQuery<R> createSelectionQuery(CriteriaQuery<R> criteria) {
159165
return queryDelegate().createSelectionQuery( criteria );

hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
import org.hibernate.query.criteria.CriteriaDefinition;
7676
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
7777
import org.hibernate.query.criteria.JpaCriteriaInsert;
78+
import org.hibernate.query.criteria.JpaCriteriaQuery;
7879
import org.hibernate.query.hql.spi.SqmQueryImplementor;
7980
import org.hibernate.query.named.NamedObjectRepository;
8081
import org.hibernate.query.named.NamedResultSetMappingMemento;
@@ -871,6 +872,10 @@ public <R> SelectionQuery<R> createSelectionQuery(String hqlString, EntityGraph<
871872
.setEntityGraph( resultGraph, GraphSemantic.LOAD );
872873
}
873874

875+
@Override
876+
public <R> JpaCriteriaQuery<R> createSelectionCriteria(String hqlString, Class<R> resultClass) {
877+
return getCriteriaBuilder().createQuery(hqlString, resultClass);
878+
}
874879

875880
@Override
876881
public <R> SelectionQuery<R> createSelectionQuery(CriteriaQuery<R> criteria) {

hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import jakarta.persistence.criteria.CriteriaDelete;
1212
import jakarta.persistence.criteria.CriteriaQuery;
1313
import jakarta.persistence.criteria.CriteriaUpdate;
14+
import org.hibernate.query.criteria.JpaCriteriaQuery;
1415

1516
/**
1617
* Contract for things that can produce instances of {@link Query} and {@link NativeQuery}.
@@ -377,6 +378,19 @@ public interface QueryProducer {
377378
*/
378379
<R> SelectionQuery<R> createSelectionQuery(String hqlString, EntityGraph<R> resultGraph);
379380

381+
/**
382+
* Transform the given HQL {@code select} query to an equivalent criteria query.
383+
*
384+
* @param hqlString The HQL {@code select} query
385+
* @param resultClass The result type of the query
386+
*
387+
* @see org.hibernate.query.criteria.HibernateCriteriaBuilder#createQuery(String, Class)
388+
*
389+
* @since 7.0
390+
*/
391+
@Incubating
392+
<R> JpaCriteriaQuery<R> createSelectionCriteria(String hqlString, Class<R> resultClass);
393+
380394
/**
381395
* Create a {@link SelectionQuery} reference for the given
382396
* {@link CriteriaQuery}.

hibernate-core/src/main/java/org/hibernate/query/criteria/CriteriaDefinition.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.hibernate.query.SelectionQuery;
1717
import org.hibernate.query.criteria.spi.HibernateCriteriaBuilderDelegate;
1818
import org.hibernate.query.common.FetchClauseType;
19+
import org.hibernate.query.restriction.Restriction;
1920
import org.hibernate.query.sqm.tree.SqmCopyContext;
2021
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
2122

@@ -495,4 +496,19 @@ public <X> JpaFunctionRoot<X> from(JpaSetReturningFunction<X> function) {
495496
public JpaCriteriaQuery<Long> createCountQuery() {
496497
return query.createCountQuery();
497498
}
499+
500+
@Override
501+
public JpaCriteriaQuery<R> setOrder(List<? extends org.hibernate.query.Order<? super R>> orderList) {
502+
return query.setOrder( orderList );
503+
}
504+
505+
@Override
506+
public JpaCriteriaQuery<R> setOrder(org.hibernate.query.Order<? super R> order) {
507+
return query.setOrder( order );
508+
}
509+
510+
@Override
511+
public JpaCriteriaQuery<R> addRestriction(Restriction<? super R> restriction) {
512+
return query.addRestriction( restriction );
513+
}
498514
}

hibernate-core/src/main/java/org/hibernate/query/criteria/JpaCriteriaQuery.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
import java.util.List;
88
import java.util.Set;
99

10+
import org.hibernate.Incubating;
11+
import org.hibernate.SharedSessionContract;
12+
import org.hibernate.query.Query;
1013
import org.hibernate.query.common.FetchClauseType;
1114

1215
import jakarta.persistence.criteria.CriteriaQuery;
@@ -17,6 +20,7 @@
1720
import jakarta.persistence.criteria.Root;
1821
import jakarta.persistence.criteria.Selection;
1922
import jakarta.persistence.metamodel.EntityType;
23+
import org.hibernate.query.restriction.Restriction;
2024

2125
/**
2226
* Extension of the JPA {@link CriteriaQuery}
@@ -34,6 +38,59 @@ public interface JpaCriteriaQuery<T> extends CriteriaQuery<T>, JpaQueryableCrite
3438
*/
3539
JpaCriteriaQuery<Long> createCountQuery();
3640

41+
/**
42+
* If the result type of this query is an entity class, add one or more
43+
* {@linkplain org.hibernate.query.Order rules} for ordering the query results.
44+
*
45+
* @param orderList one or more instances of {@link org.hibernate.query.Order}
46+
*
47+
* @see org.hibernate.query.Order
48+
*
49+
* @since 7.0
50+
*/
51+
@Incubating
52+
JpaCriteriaQuery<T> setOrder(List<? extends org.hibernate.query.Order<? super T>> orderList);
53+
54+
/**
55+
* If the result type of this query is an entity class, add a
56+
* {@linkplain org.hibernate.query.Order rule} for ordering the query results.
57+
*
58+
* @param order an instance of {@link org.hibernate.query.Order}
59+
*
60+
* @see org.hibernate.query.Order
61+
*
62+
* @since 7.0
63+
*/
64+
@Incubating
65+
JpaCriteriaQuery<T> setOrder(org.hibernate.query.Order<? super T> order);
66+
67+
/**
68+
* If the result type of this query is an entity class, add a
69+
* {@linkplain Restriction rule} for restricting the query results.
70+
*
71+
* @param restriction an instance of {@link Restriction}
72+
*
73+
* @see Restriction
74+
*
75+
* @since 7.0
76+
*/
77+
@Incubating
78+
JpaCriteriaQuery<T> addRestriction(Restriction<? super T> restriction);
79+
80+
/**
81+
* Creates a query for this criteria query.
82+
*
83+
* @param session the Hibernate session
84+
*
85+
* @see SharedSessionContract#createQuery(CriteriaQuery)
86+
*
87+
* @since 7.0
88+
*/
89+
@Incubating
90+
default Query<T> toQuery(SharedSessionContract session) {
91+
return session.createQuery( this );
92+
}
93+
3794
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3895
// Limit/Offset/Fetch clause
3996

hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -841,7 +841,7 @@ public Map<JpaCriteriaParameter<?>, SqmJpaCriteriaParameterWrapper<?>> getJpaCri
841841
}
842842
}
843843

844-
static JpaOrder sortSpecification(SqmSelectStatement<?> sqm, Order<?> order) {
844+
public static JpaOrder sortSpecification(SqmSelectStatement<?> sqm, Order<?> order) {
845845
final List<SqmSelectableNode<?>> items = sqm.getQuerySpec().getSelectClause().getSelectionItems();
846846
final int element = order.getElement();
847847
if ( element < 1) {

hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.hibernate.query.criteria.JpaExpression;
1818
import org.hibernate.query.criteria.JpaSelection;
1919
import org.hibernate.query.common.FetchClauseType;
20+
import org.hibernate.query.restriction.Restriction;
2021
import org.hibernate.query.sqm.NodeBuilder;
2122
import org.hibernate.query.sqm.SemanticQueryWalker;
2223
import org.hibernate.query.sqm.SqmQuerySource;
@@ -43,6 +44,8 @@
4344
import static java.util.Collections.emptySet;
4445
import static java.util.Collections.unmodifiableList;
4546
import static java.util.Collections.unmodifiableSet;
47+
import static java.util.stream.Collectors.toList;
48+
import static org.hibernate.query.sqm.internal.SqmUtil.sortSpecification;
4649
import static org.hibernate.query.sqm.spi.SqmCreationHelper.combinePredicates;
4750
import static org.hibernate.query.sqm.SqmQuerySource.CRITERIA;
4851
import static org.hibernate.query.sqm.tree.SqmCopyContext.noParamCopyContext;
@@ -553,6 +556,25 @@ public SqmSelectStatement<Long> createCountQuery() {
553556
}
554557
}
555558

559+
@Override
560+
public JpaCriteriaQuery<T> setOrder(List<? extends org.hibernate.query.Order<? super T>> orderList) {
561+
orderBy( orderList.stream().map( order -> sortSpecification( this, order ) )
562+
.collect( toList() ) );
563+
return this;
564+
}
565+
566+
@Override
567+
public JpaCriteriaQuery<T> setOrder(org.hibernate.query.Order<? super T> order) {
568+
orderBy( sortSpecification( this, order ) );
569+
return this;
570+
}
571+
572+
@Override
573+
public JpaCriteriaQuery<T> addRestriction(Restriction<? super T> restriction) {
574+
restriction.apply( this, this.<T>getRoot( 0, getResultType() ) );
575+
return this;
576+
}
577+
556578
private <S> void aliasSelections(SqmQueryPart<S> queryPart) {
557579
if ( queryPart.isSimpleQueryPart() ) {
558580
final SqmQuerySpec<S> querySpec = queryPart.getFirstQuerySpec();

hibernate-core/src/test/java/org/hibernate/orm/test/join/JoinAndFetchWithCriteriaSelectionQueryTest.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import org.hibernate.metamodel.model.domain.EntityDomainType;
1313
import org.hibernate.query.Order;
1414

15+
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
16+
import org.hibernate.query.criteria.JpaCriteriaQuery;
1517
import org.hibernate.testing.jdbc.SQLStatementInspector;
1618
import org.hibernate.testing.orm.junit.DomainModel;
1719
import org.hibernate.testing.orm.junit.Jira;
@@ -120,8 +122,8 @@ void fetchAfterJoinWithoutWhereClauseTest(SessionFactoryScope scope) {
120122
final SQLStatementInspector inspector = scope.getCollectingStatementInspector();
121123
inspector.clear();
122124
scope.inTransaction( session -> {
123-
CriteriaBuilder cb = session.getCriteriaBuilder();
124-
CriteriaQuery<Book> query = cb.createQuery( Book.class );
125+
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
126+
JpaCriteriaQuery<Book> query = cb.createQuery( Book.class );
125127
Root<Book> from = query.from( Book.class );
126128

127129
// The join MUST BE created before the fetch for this test
@@ -135,9 +137,9 @@ void fetchAfterJoinWithoutWhereClauseTest(SessionFactoryScope scope) {
135137
SingularAttribute<? super Book, ?> title = bookType.findSingularAttribute( "title" );
136138
query.select( from ).distinct( true );
137139

138-
List<Book> books = session
139-
.createSelectionQuery( query )
140+
List<Book> books = query
140141
.setOrder( Order.asc( title ) )
142+
.toQuery( session )
141143
.getResultList();
142144
assertThat( books ).containsExactly( leftHand, timeWar );
143145
assertThat( Hibernate.isInitialized( books.get( 0 ).getAuthors() ) ).isTrue();
@@ -154,8 +156,8 @@ void fetchBeforeJoinWithoutWhereClauseTest(SessionFactoryScope scope) {
154156
final SQLStatementInspector inspector = scope.getCollectingStatementInspector();
155157
inspector.clear();
156158
scope.inTransaction( session -> {
157-
CriteriaBuilder cb = session.getCriteriaBuilder();
158-
CriteriaQuery<Book> query = cb.createQuery( Book.class );
159+
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
160+
JpaCriteriaQuery<Book> query = cb.createQuery( Book.class );
159161
Root<Book> from = query.from( Book.class );
160162

161163
// The fetch MUST BE created before the join for this test
@@ -169,9 +171,9 @@ void fetchBeforeJoinWithoutWhereClauseTest(SessionFactoryScope scope) {
169171
SingularAttribute<? super Book, ?> title = bookType.findSingularAttribute( "title" );
170172
query.select( from ).distinct( true );
171173

172-
List<Book> books = session
173-
.createSelectionQuery( query )
174+
List<Book> books = query
174175
.setOrder( Order.asc( title ) )
176+
.toQuery( session )
175177
.getResultList();
176178
assertThat( books ).containsExactly( leftHand, timeWar );
177179
assertThat( Hibernate.isInitialized( books.get( 0 ).getAuthors() ) ).isTrue();

0 commit comments

Comments
 (0)