Skip to content

Commit 9fb5daa

Browse files
authored
Merge branch 'main' into HHH-17002
2 parents 482b3f0 + 646b876 commit 9fb5daa

File tree

912 files changed

+7777
-7498
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

912 files changed

+7777
-7498
lines changed

Jenkinsfile

+3-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ stage('Configure') {
4040
// Don't build with HANA by default, but only do it nightly until we receive a 3rd instance
4141
// new BuildEnvironment( dbName: 'hana_cloud', dbLockableResource: 'hana-cloud', dbLockResourceAsHost: true ),
4242
new BuildEnvironment( node: 's390x' ),
43-
new BuildEnvironment( dbName: 'tidb', node: 'tidb',
44-
notificationRecipients: '[email protected]' ),
4543
// We want to enable preview features when testing newer builds of OpenJDK:
4644
// even if we don't use these features, just enabling them can cause side effects
4745
// and it's useful to test that.
@@ -65,6 +63,9 @@ stage('Configure') {
6563
if ( pullRequest.labels.contains( 'sybase' ) ) {
6664
this.environments.add( new BuildEnvironment( dbName: 'sybase_jconn' ) )
6765
}
66+
if ( pullRequest.labels.contains( 'tidb' ) ) {
67+
this.environments.add( new BuildEnvironment( dbName: 'tidb', node: 'tidb', notificationRecipients: '[email protected]' ) )
68+
}
6869
}
6970

7071
helper.configure {

documentation/documentation.gradle

+40
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,45 @@ def renderIntegrationGuidesTask = tasks.register( "renderIntegrationGuides" ) {
737737
}
738738

739739

740+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
741+
// What's New Guide
742+
743+
def whatsNewGuideSourceStagingDir = layout.buildDirectory.dir( "tmp/asciidoc/whats-new" )
744+
745+
def copyWhatsNewTask = tasks.register( "copyWhatsNew", Copy ) {task ->
746+
group = "Documentation"
747+
description = "Copies whats-new.adoc in preparation for rendering."
748+
749+
inputs.property "hibernate-version", hibernateVersion
750+
751+
from rootProject.layout.projectDirectory.file( "whats-new.adoc" )
752+
into whatsNewGuideSourceStagingDir
753+
}
754+
755+
def renderWhatsNewTask = tasks.register( "renderWhatsNew", AsciidoctorTask ) {
756+
group = "Documentation"
757+
description = "Renders the What's New guide in HTML format using Asciidoctor."
758+
759+
dependsOn copyWhatsNewTask
760+
inputs.property "hibernate-version", hibernateVersion
761+
762+
sourceDir = whatsNewGuideSourceStagingDir
763+
764+
outputDir = project.layout.buildDirectory.dir( 'asciidoc/whats-new' )
765+
766+
attributes linkcss: true,
767+
stylesheet: "css/hibernate.css"
768+
769+
resources {
770+
from( 'src/main/style/asciidoctor' ) {
771+
include 'images/**'
772+
}
773+
from( 'src/main/style/asciidoctor' ) {
774+
include 'css/**'
775+
}
776+
}
777+
}
778+
740779
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
741780
// Migration Guide
742781

@@ -853,6 +892,7 @@ def buildDocsTask = tasks.register( 'buildDocs' ) { task ->
853892
task.dependsOn renderTopicalGuidesTask
854893
task.dependsOn generateReportsTask
855894
task.dependsOn renderMigrationGuideTask
895+
task.dependsOn renderWhatsNewTask
856896
}
857897

858898
//noinspection GroovyUnusedAssignment

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]]

documentation/src/main/asciidoc/userguide/Hibernate_User_Guide.adoc

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ include::chapters/caching/Caching.adoc[]
3131
include::chapters/events/Events.adoc[]
3232
include::chapters/query/hql/Query.adoc[]
3333
include::chapters/query/hql/QueryLanguage.adoc[]
34+
include::chapters/query/programmatic/QuerySpecification.adoc[]
3435
include::chapters/query/criteria/Criteria.adoc[]
3536
include::chapters/query/criteria/CriteriaExtensions.adoc[]
3637
include::chapters/query/native/Native.adoc[]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
[[QuerySpecification]]
2+
== Programmatic Query Specification
3+
:root-project-dir: ../../../../../../../..
4+
5+
Hibernate offers an API for creating a representation of a query, adjusting that representation programmatically, and then creating an executable form of the query. The idea is similar in concept to <<chapters/query/criteria/Criteria.adoc#criteria,criteria queries>>, but focused on ease-of-use and less verbosity.
6+
7+
There is support for both <<SelectionSpecification,selection>> and <<MutationSpecification,mutation>> queries via the `SelectionSpecification` and `MutationSpecification` contracts, respectively. These can be obtained from both `Session` and `StatelessSession`.
8+
9+
[NOTE]
10+
====
11+
These APIs are new in 7.0 and considered incubating.
12+
====
13+
14+
[[SelectionSpecification]]
15+
=== SelectionSpecification
16+
17+
A `SelectionSpecification` allows to iteratively build a query from a "base", adjust the query by adding sorting and restrictions and finally creating an executable <<hql-SelectionQuery,`SelectionQuery`>>. We can use HQL as the base -
18+
19+
.SelectionSpecification from HQL
20+
====
21+
[source, java, indent=0]
22+
----
23+
SelectionSpecification<Book> spec = session.createSelectionSpecification(
24+
"from Book",
25+
Book.class
26+
);
27+
----
28+
====
29+
30+
or a root entity as the base -
31+
32+
.SelectionSpecification from root entity
33+
====
34+
[source, java, indent=0]
35+
----
36+
SelectionSpecification<Book> spec = session.createSelectionSpecification(Book.class);
37+
----
38+
====
39+
40+
Once we have the `SelectionSpecification` we can adjust the query adding restrictions and sorting -
41+
42+
.Adjusting the SelectionSpecification
43+
====
44+
[source, java, indent=0]
45+
----
46+
// from here we can augment the base query "from Book",
47+
// with either restrictions
48+
spec.restriction(
49+
Restriction.restrict(
50+
Book_.suggestedCost,
51+
Range.closed(10.00, 19.99)
52+
)
53+
);
54+
55+
// or here with some sorting
56+
spec.order(
57+
Order.asc(Book_.suggestedCost)
58+
)
59+
----
60+
====
61+
62+
[NOTE]
63+
====
64+
Notice that generally the JPA static metamodel is a convenient and type-safe way to help build these sorting and restriction references.
65+
====
66+
67+
After adjusting the query, we can obtain the executable `SelectionQuery`:
68+
69+
.Using the SelectionSpecification
70+
====
71+
[source, java, indent=0]
72+
----
73+
SelectionQuery<Book> qry = ds.createQuery();
74+
List<Book> books = qry.getResultList();
75+
----
76+
====
77+
78+
These calls can even be chained, e.g.
79+
80+
.Example of chained calls
81+
====
82+
[source, java, indent=0]
83+
----
84+
SelectionQuery<Book> qry = session.createSelectionSpecification(
85+
"from Book",
86+
Book.class
87+
).restriction(
88+
Restriction.restrict(
89+
Book_.suggestedCost,
90+
Range.closed(10.00, 19.99)
91+
)
92+
).order(
93+
Order.asc(Book_.suggestedCost)
94+
).createQuery();
95+
----
96+
====
97+
98+
[NOTE]
99+
====
100+
We expect, in future releases, to add the ability to handle pagination.
101+
102+
We also expect to add the ability to use <<criteria,Criteria>> references as the base. Possibly even `TypedQueryReference` references.
103+
====
104+
105+
[[MutationSpecification]]
106+
=== MutationSpecification
107+
108+
There is also support for mutation queries through `MutationSpecification`.
109+
At the moment, only update and delete queries are supported. E.g.
110+
111+
.MutationQuery example
112+
====
113+
[source, java, indent=0]
114+
----
115+
MutationQuery<Book> qry = session.createMutationSpecification(
116+
"delete Book",
117+
Book.class
118+
).restriction(
119+
Restriction.restrict(
120+
Book_.suggestedCost,
121+
Range.closed(10.00, 19.99)
122+
)
123+
).createQuery();
124+
----
125+
====

hibernate-agroal/src/test/java/org/hibernate/test/agroal/AgroalTransactionIsolationConfigTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
package org.hibernate.test.agroal;
66

77
import org.hibernate.community.dialect.AltibaseDialect;
8-
import org.hibernate.dialect.TiDBDialect;
8+
import org.hibernate.community.dialect.TiDBDialect;
99
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
1010
import org.hibernate.agroal.internal.AgroalConnectionProvider;
1111

hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3p0TransactionIsolationConfigTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import org.hibernate.c3p0.internal.C3P0ConnectionProvider;
1010
import org.hibernate.community.dialect.AltibaseDialect;
1111
import org.hibernate.dialect.SybaseASEDialect;
12-
import org.hibernate.dialect.TiDBDialect;
12+
import org.hibernate.community.dialect.TiDBDialect;
1313
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
1414
import org.hibernate.service.spi.ServiceRegistryImplementor;
1515

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseSqlAstTranslator.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ protected void renderComparison(Expression lhs, ComparisonOperator operator, Exp
6464
@Override
6565
public void visitOver(Over<?> over) {
6666
final Expression expression = over.getExpression();
67-
if ( expression instanceof FunctionExpression && "row_number".equals( ( (FunctionExpression) expression ).getFunctionName() ) ) {
67+
if ( expression instanceof FunctionExpression functionExpression
68+
&& "row_number".equals( functionExpression.getFunctionName() ) ) {
6869
if ( over.getPartitions().isEmpty() && over.getOrderList().isEmpty()
6970
&& over.getStartKind() == FrameKind.UNBOUNDED_PRECEDING
7071
&& over.getEndKind() == FrameKind.CURRENT_ROW

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java

+9
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@
3636
import org.hibernate.dialect.pagination.OffsetFetchLimitHandler;
3737
import org.hibernate.dialect.sequence.PostgreSQLSequenceSupport;
3838
import org.hibernate.dialect.sequence.SequenceSupport;
39+
import org.hibernate.dialect.type.PgJdbcHelper;
40+
import org.hibernate.dialect.type.PostgreSQLArrayJdbcTypeConstructor;
41+
import org.hibernate.dialect.type.PostgreSQLCastingInetJdbcType;
42+
import org.hibernate.dialect.type.PostgreSQLCastingIntervalSecondJdbcType;
43+
import org.hibernate.dialect.type.PostgreSQLCastingJsonArrayJdbcTypeConstructor;
44+
import org.hibernate.dialect.type.PostgreSQLCastingJsonJdbcType;
45+
import org.hibernate.dialect.type.PostgreSQLEnumJdbcType;
46+
import org.hibernate.dialect.type.PostgreSQLOrdinalEnumJdbcType;
47+
import org.hibernate.dialect.type.PostgreSQLUUIDJdbcType;
3948
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
4049
import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy;
4150
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import org.hibernate.community.dialect.sequence.LegacyDB2SequenceSupport;
2929
import org.hibernate.dialect.DB2Dialect;
3030
import org.hibernate.dialect.DB2GetObjectExtractor;
31-
import org.hibernate.dialect.DB2StructJdbcType;
31+
import org.hibernate.dialect.type.DB2StructJdbcType;
3232
import org.hibernate.dialect.DatabaseVersion;
3333
import org.hibernate.dialect.Dialect;
3434
import org.hibernate.dialect.DmlTargetColumnQualifierSupport;

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java

+3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
import org.hibernate.dialect.sequence.SequenceSupport;
3535
import org.hibernate.dialect.temptable.TemporaryTable;
3636
import org.hibernate.dialect.temptable.TemporaryTableKind;
37+
import org.hibernate.dialect.type.H2DurationIntervalSecondJdbcType;
38+
import org.hibernate.dialect.type.H2JsonArrayJdbcTypeConstructor;
39+
import org.hibernate.dialect.type.H2JsonJdbcType;
3740
import org.hibernate.dialect.unique.CreateTableUniqueDelegate;
3841
import org.hibernate.dialect.unique.UniqueDelegate;
3942
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;

0 commit comments

Comments
 (0)