Skip to content

Commit ed3a4dd

Browse files
committed
HHH-19364 update Short Guide
1 parent f1d1ef5 commit ed3a4dd

File tree

1 file changed

+72
-18
lines changed

1 file changed

+72
-18
lines changed

documentation/src/main/asciidoc/introduction/Interacting.adoc

+72-18
Original file line numberDiff line numberDiff line change
@@ -1048,54 +1048,108 @@ In Hibernate 7, there's a new option, a very ergonomic API for programmatically
10481048
This new API:
10491049

10501050
- isn't part of the Criteria Query API, and so we don't need a `CriteriaQuery` object to make use of it,
1051-
- works with both HQL and Criteria queries, and even with <<named-queries,named HQL queries>>, and
1051+
- _does_ make use of the JPA <<metamodel-generator,static metamodel>> for type safety,
1052+
- works with both HQL and Criteria queries, and
10521053
- is optimized for the case of a query which returns its single root entity.
10531054

10541055
[source,java]
10551056
----
1056-
var query = session.createSelectionQuery("from Book where year(publicationDate) > 2000", Book.class);
1057-
if (titlePattern != null) {
1058-
query.addRestriction(Restriction.like(Book_.title, namePattern));
1059-
}
1060-
if (isbns != null && !isbns.isEmpty()) {
1061-
query.addRestriction(Restriction.in(Book_.isbn, isbns))
1062-
}
1063-
query.setOrder(List.of(Order.asc(Book_.title), Order.asc(Book_.isbn)));
1064-
List<Book> matchingBooks = query.getResultList();
1057+
var selection =
1058+
SelectionSpecification.create(Book.class,
1059+
// an optional base query, written in HQL:
1060+
"from Book where year(publicationDate) > 2000");
1061+
1062+
// add programmatic restrictions:
1063+
if (titlePattern != null)
1064+
selection.addRestriction(Restriction.like(Book_.title, namePattern));
1065+
if (isbns != null && !isbns.isEmpty())
1066+
selection.addRestriction(Restriction.in(Book_.isbn, isbns));
10651067
1068+
// add programmatic ordering:
1069+
if (orderByTitle) selection.addOrdering(Order.asc(Book_.title));
1070+
if (orderByIsbn) selection.addOrdering(Order.asc(Book_.isbn));
1071+
1072+
// add programmatic association fetching:
1073+
if (fetchPublisher) selection.addFetching(Path.from(Book.class).to(Book_.publisher));
1074+
1075+
// execute the query in the given session:
1076+
List<Book> matchingBooks = selection.createQuery(session).getResultList();
10661077
----
10671078

10681079
Notice that:
10691080

10701081
- The link:{doc-javadoc-url}org/hibernate/query/restriction/Restriction.html[`Restriction`] interface has static methods for constructing a variety of different kinds of restriction in a completely typesafe way.
10711082
- Similarly, the link:{doc-javadoc-url}org/hibernate/query/Order.html[`Order`] class has a variety of static methods for constructing different kinds of ordering criteria.
10721083

1073-
We need the following methods of `SelectionQuery`:
1084+
We need the following methods of link:{doc-javadoc-url}org/hibernate/query/programmatic/SelectionSpecification.html[`SelectionSpecification`]:
10741085

10751086
.Methods for query restriction and ordering
1076-
[%breakable,cols="30,~,^15"]
1087+
[%breakable,cols="20,~]
10771088
|===
1078-
| Method name | Purpose | JPA-standard
1089+
| Method name | Purpose
10791090

1080-
| `addRestriction()` | Add a restriction on the query results | &#10006;
1081-
| `setOrder()` | Specify how the query results should be ordered | &#10006;
1091+
| `addRestriction()` | Add a restriction on the query results
1092+
| `setOrder()`, `addOrder()` | Specify how the query results should be ordered
1093+
| `addFetching()` | Add a fetched association
1094+
| `addAugmentation()` | Add a custom function which directly manipulates the query
10821095
|===
10831096

1084-
Unfortunately, `Restriction` and `Order` can't be used with JPA's `TypedQuery` interface, and JPA has no built-in alternative, so if we're using `EntityManager`, we need to call `unwrap()` to obtain a `SelectionQuery`.
1085-
10861097
Alternatively, `Restriction` and `Order` can be used with <<paging-and-ordering,generated query or finder methods>>, and even with link:{doc-data-repositories-url}[Jakarta Data repositories].
10871098

10881099
The interface link:{doc-javadoc-url}org/hibernate/query/restriction/Path.html[`Path`] may be used to express restrictions on fields of an embedded or associated entity class.
10891100

10901101
[source,java]
10911102
----
10921103
List<Book> booksForPublisher =
1093-
session.createSelectionQuery("from Book", Book.class)
1104+
SelectionSpecification.create(Book.class)
10941105
.addRestriction(Path.from(Book.class).to(Book_.publisher).to(Publisher_.name)
10951106
.equalTo(publisherName))
1107+
.addFetching(Path.from(Book.class).to(Book_.publisher))
1108+
.createQuery(session)
10961109
.getResultList();
10971110
----
10981111

1112+
When `Restriction`, `Path`, and `Order` aren't expressive enough, we can _augment_ the query by manipulating its representation as a criteria:
1113+
1114+
[source,java]
1115+
----
1116+
var books =
1117+
SelectionSpecification.create(Book.class)
1118+
.addAugmentation((builder, query, book) ->
1119+
// augment the query via JPA Criteria API
1120+
query.where(builder.like(book.get(Book_.title), titlePattern)))
1121+
.orderBy(builder.asc(book.get(Book_.isbn)))
1122+
.createQuery(session)
1123+
.getResultList();
1124+
----
1125+
1126+
For really advanced cases, `addAugmentation()` works quite nicely with <<criteria-definition,`CriteriaDefinition`>>.
1127+
1128+
[source,java]
1129+
----
1130+
var books =
1131+
SelectionSpecification.create(Book.class)
1132+
.addAugmentation((builder, query, book) ->
1133+
// eliminate explicit references to 'builder'
1134+
new CriteriaDefinition<>(query) {{
1135+
where(like(entity.get(BasicEntity_.title), titlePattern),
1136+
greaterThan(book.get(Book_.pages), minPages));
1137+
orderBy(asc(book.get(Book_.isbn)));
1138+
}}
1139+
)
1140+
.createQuery(session)
1141+
.getResultList();
1142+
----
1143+
1144+
However, we emphasize that this API shines in cases where complex manipulations are _not_ required.
1145+
1146+
[NOTE]
1147+
====
1148+
`SelectionSpecification` (similar to its friend `MutationSpecification`) may be used in cases where a query returns a single "root" entity, possibly with some fetched associations.
1149+
It is not useful in cases where a query should return multiple entities, a projection of entity fields, or an aggregation.
1150+
For such cases, the full Criteria API is appropriate.
1151+
====
1152+
10991153
Programmatic restrictions, and especially programmatic ordering, are often used together with pagination.
11001154

11011155
[[pagination]]

0 commit comments

Comments
 (0)