HHH-15055 - Document SelectionQuery and MutationQuery

This commit is contained in:
Steve Ebersole 2022-02-05 10:49:54 -06:00
parent a7da40709c
commit 86cdf67016
5 changed files with 252 additions and 0 deletions

View File

@ -28,6 +28,8 @@ Each serves a different purpose depending on the expected type of the query resu
====
The chapter 6 (i.e., Criteria API) of the Jakarta Persistence Specification already contains a decent amount of reference material pertaining to the various parts of a criteria query.
So rather than duplicate all that content here, let's instead look at some of the more widely anticipated usages of the API.
====
[[criteria-typedquery]]

View File

@ -21,6 +21,12 @@ However, HQL is the most convenient option for most people most of the time.
The actual query language itself is discussed the <<chapters/query/criteria/QueryLanguage.adoc#query-language,next chapter>>.
This chapter describes the Java APIs for executing HQL and JPQL queries.
Most of this chapter is dedicated to discussing `org.hibernate.query.Query`, `jakarta.persistence.Query` and
`jakarta.persistence.TypedQuery`. These `Query` contracts mix the ability to perform selections as well mutations.
Hibernate additionally offers the more targeted `SelectionQuery` and `MutationQuery` contracts. See
<<hql-SelectionQuery>> and <<hql-MutationQuery>> for additional details.
[[hql-examples-domain-model]]
=== Example domain model
@ -573,3 +579,71 @@ The setting gives the maximum number of `ParameterMetadataImpl` instances mainta
Now, if you have many JPQL or Criteria API queries, it's a good idea to increase the query plan cache size so that the vast majority of executing entity queries can skip the compilation phase, therefore reducing execution time.
To get a better understanding of the query plan cache effectiveness, Hibernate offers several statistics you can use. For more details, check out the <<chapters/statistics/Statistics.adoc#statistics-query-plan-cache,Query plan cache statistics>> section.
[[hql-SelectionQuery]]
=== SelectionQuery
Hibernate's `SelectionQuery` contract is similar to `Query` but only exposes methods which are relevant to selection queries. For example,
it does not expose a `#executeUpdate` method. This allows for earlier validation of the query as a selection.
[[hql-examples-selection-query]]
.Selection query validation
====
[source, JAVA, indent=0]
----
include::{sourcedir}/SelectionQueryExampleTests.java[tags=example-hql-selection-query]
include::{sourcedir}/SelectionQueryExampleTests.java[tags=example-hql-selection-query-query]
----
====
`SelectionQuery` may also be used with named-queries
[[hql-examples-named-selection-query]]
.NamedQuery selection validation
====
[source, JAVA, indent=0]
----
include::{sourcedir}/SelectionQueryExampleTests.java[tags=example-hql-named-selection-query]
include::{sourcedir}/SelectionQueryExampleTests.java[tags=example-hql-named-selection-query-query]
----
====
[[hql-MutationQuery]]
=== MutationQuery
Along the same lines as `SelectionQuery`, `MutationQuery` is similar to `Query` but only exposes methods which are relevant to mutation queries.
For example, in terms of execution, it only exposes `#executeUpdate` method. This allows for earlier validation of the query as a mutation.
[[hql-examples-mutation-query]]
.Mutation query validation
====
[source, JAVA, indent=0]
----
include::{sourcedir}/MutationQueryExampleTests.java[tags=example-hql-mutation-query]
include::{sourcedir}/MutationQueryExampleTests.java[tags=example-hql-mutation-query-query]
----
====
`MutationQuery` may also be used with named-queries
[[hql-examples-named-mutation-query]]
.NamedQuery mutation validation
====
[source, JAVA, indent=0]
----
include::{sourcedir}/MutationQueryExampleTests.java[tags=example-hql-named-mutation-query]
include::{sourcedir}/MutationQueryExampleTests.java[tags=example-hql-named-mutation-query-query]
----
====

View File

@ -160,6 +160,10 @@ import jakarta.persistence.Version;
}
)
//end::jpa-read-only-entities-native-example[]
@NamedQuery(
name = "delete_person",
query = "delete Person"
)
//tag::sql-sp-ref-cursor-oracle-named-query-example[]
@NamedStoredProcedureQuery(
name = "sp_person_phones",

View File

@ -0,0 +1,86 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.userguide.hql;
import org.hibernate.query.MutationQuery;
import org.hibernate.query.Query;
import org.hibernate.query.SelectionQuery;
import org.hibernate.userguide.model.Account;
import org.hibernate.userguide.model.Call;
import org.hibernate.userguide.model.CreditCardPayment;
import org.hibernate.userguide.model.Person;
import org.hibernate.userguide.model.Phone;
import org.hibernate.userguide.model.WireTransferPayment;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.FailureExpected;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
/**
* @author Steve Ebersole
*/
@DomainModel(
annotatedClasses = {
Person.class,
Phone.class,
Call.class,
Account.class,
CreditCardPayment.class,
WireTransferPayment.class
}
)
@SessionFactory
public class MutationQueryExampleTests {
@Test
@FailureExpected( reason = "Illegal mutation query" )
public void queryTest(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
//tag::example-hql-mutation-query-query[]
// cannot be validated until execution
Query<Person> query = session.createQuery( "select p from Person p", Person.class );
query.executeUpdate();
//end::example-hql-mutation-query-query[]
} );
}
@Test
@FailureExpected( reason = "Illegal mutation query" )
public void selectionQueryTest(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
//tag::example-hql-mutation-query[]
// can be validated while creating the MutationQuery
MutationQuery badQuery = session.createMutationQuery( "select p from Person p" );
//end::example-hql-mutation-query[]
} );
}
@Test
@FailureExpected( reason = "Illegal mutation query" )
public void namedSelectionQueryTest(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
//tag::example-hql-named-mutation-query[]
// can be validated while creating the MutationQuery
MutationQuery badQuery = session.createNamedMutationQuery( "get_person_by_name" );
//end::example-hql-named-mutation-query[]
} );
}
@Test
@FailureExpected( reason = "Illegal mutation query" )
public void namedQueryTest(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
//tag::example-hql-named-mutation-query-query[]
// cannot be validated until execution
Query query = session.createNamedQuery( "get_person_by_name" );
query.getResultList();
//end::example-hql-named-mutation-query-query[]
} );
}
}

View File

@ -0,0 +1,86 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.userguide.hql;
import org.hibernate.query.Query;
import org.hibernate.query.SelectionQuery;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.userguide.model.Account;
import org.hibernate.userguide.model.Call;
import org.hibernate.userguide.model.CreditCardPayment;
import org.hibernate.userguide.model.Person;
import org.hibernate.userguide.model.Phone;
import org.hibernate.userguide.model.WireTransferPayment;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.FailureExpected;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
/**
* @author Steve Ebersole
*/
@DomainModel(
annotatedClasses = {
Person.class,
Phone.class,
Call.class,
Account.class,
CreditCardPayment.class,
WireTransferPayment.class
}
)
@SessionFactory
public class SelectionQueryExampleTests {
@Test
@FailureExpected( reason = "Illegal selection query" )
public void selectionQueryTest(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
//tag::example-hql-selection-query[]
// can be validated while creating the SelectionQuery
SelectionQuery<?> badQuery = session.createSelectionQuery( "delete Person" );
//end::example-hql-selection-query[]
} );
}
@Test
@FailureExpected( reason = "Illegal selection query" )
public void queryTest(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
//tag::example-hql-selection-query-query[]
// cannot be validated until execution
Query query = session.createQuery( "delete Person" );
query.getResultList();
//end::example-hql-selection-query-query[]
} );
}
@Test
@FailureExpected( reason = "Illegal selection query" )
public void namedSelectionQueryTest(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
//tag::example-hql-named-selection-query[]
// can be validated while creating the SelectionQuery
SelectionQuery<?> badQuery = session.getNamedQuery( "delete_Person" );
//end::example-hql-named-selection-query[]
} );
}
@Test
@FailureExpected( reason = "Illegal selection query" )
public void namedQueryTest(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
//tag::example-hql-named-selection-query-query[]
// cannot be validated until execution
Query query = session.getNamedQuery( "delete_Person" );
query.getResultList();
//end::example-hql-named-selection-query-query[]
} );
}
}