diff --git a/data-connection-jdbc/build.gradle b/data-connection-jdbc/build.gradle index e4e7f78470b..7df18343c9b 100644 --- a/data-connection-jdbc/build.gradle +++ b/data-connection-jdbc/build.gradle @@ -21,33 +21,18 @@ dependencies { testImplementation mnReactor.micronaut.reactor - testImplementation(mnTestResources.testcontainers.mysql) - testImplementation(mnTestResources.testcontainers.mariadb) testImplementation(mnTestResources.testcontainers.postgres) - testImplementation(mnTestResources.testcontainers.mssql) - testImplementation(mnTestResources.testcontainers.oracle.xe) testCompileOnly mn.micronaut.inject.groovy testImplementation mn.micronaut.http.netty testRuntimeOnly mnSql.micronaut.jdbc.tomcat testRuntimeOnly mnSql.h2 - testRuntimeOnly mnSql.mariadb.java.client - testRuntimeOnly mnSql.ojdbc11 - testRuntimeOnly mnSql.mysql.connector.java testRuntimeOnly mnSql.postgresql - testRuntimeOnly mnSql.mssql.jdbc testRuntimeOnly mn.snakeyaml - testResourcesService mnSql.mariadb.java.client - testResourcesService mnSql.ojdbc11 - testResourcesService mnSql.mysql.connector.java testResourcesService mnSql.postgresql - testResourcesService mnSql.mssql.jdbc - testImplementation libs.micronaut.testresources.client - - testRuntimeOnly mnSerde.micronaut.serde.oracle.jdbc.json } micronaut { diff --git a/data-jdbc/src/test/resources/application.yml b/data-jdbc/src/test/resources/application.yml index 5807b8f041d..edca537035f 100644 --- a/data-jdbc/src/test/resources/application.yml +++ b/data-jdbc/src/test/resources/application.yml @@ -3,6 +3,7 @@ test-resources: mssql: accept-license: true startup-timeout: 300s + image-name: mcr.microsoft.com/mssql/server:2022-latest mariadb: startup-timeout: 300s mysql: diff --git a/data-model/src/main/java/io/micronaut/data/repository/jpa/criteria/SpecificationComposition.java b/data-model/src/main/java/io/micronaut/data/repository/jpa/criteria/SpecificationComposition.java index dbc16969bfa..015f62e8a56 100644 --- a/data-model/src/main/java/io/micronaut/data/repository/jpa/criteria/SpecificationComposition.java +++ b/data-model/src/main/java/io/micronaut/data/repository/jpa/criteria/SpecificationComposition.java @@ -15,6 +15,7 @@ */ package io.micronaut.data.repository.jpa.criteria; +import io.micronaut.core.annotation.Internal; import io.micronaut.core.annotation.NonNull; import io.micronaut.core.annotation.Nullable; import jakarta.persistence.criteria.CriteriaBuilder; @@ -37,7 +38,8 @@ * @author Denis Stepanov * @since 3.2 */ -class SpecificationComposition { +@Internal +final class SpecificationComposition { @NonNull static QuerySpecification composed(@Nullable QuerySpecification lhs, @Nullable QuerySpecification rhs, Combiner combiner) { diff --git a/data-r2dbc/src/test/resources/application.yaml b/data-r2dbc/src/test/resources/application.yaml index d8aa464e643..838b600c7fd 100644 --- a/data-r2dbc/src/test/resources/application.yaml +++ b/data-r2dbc/src/test/resources/application.yaml @@ -3,6 +3,7 @@ test-resources: mssql: accept-license: true startup-timeout: 300s + image-name: mcr.microsoft.com/mssql/server:2022-latest mariadb: startup-timeout: 300s mysql: diff --git a/data-tx-hibernate/src/test/groovy/io/micronaut/transaction/hibernate6/SqlServerHibernateTransactionSpec.groovy b/data-tx-hibernate/src/test/groovy/io/micronaut/transaction/hibernate6/SqlServerHibernateTransactionSpec.groovy index 8b1036f1952..680fccdf723 100644 --- a/data-tx-hibernate/src/test/groovy/io/micronaut/transaction/hibernate6/SqlServerHibernateTransactionSpec.groovy +++ b/data-tx-hibernate/src/test/groovy/io/micronaut/transaction/hibernate6/SqlServerHibernateTransactionSpec.groovy @@ -17,7 +17,8 @@ class SqlServerHibernateTransactionSpec extends HibernateTransactionSpec impleme "datasources.default.name" : "mymssqldb", 'jpa.default.properties.hibernate.hbm2ddl.auto' : 'create-drop', 'jpa.default.properties.hibernate.dialect' : 'org.hibernate.dialect.SQLServerDialect', - 'test-resources.containers.mssql.accept-license' : 'true' + 'test-resources.containers.mssql.accept-license' : 'true', + 'test-resources.containers.mssql.image-name' : 'mcr.microsoft.com/mssql/server:2022-latest' ] } diff --git a/src/main/docs/guide/dbc/dbcCriteriaSpecifications.adoc b/src/main/docs/guide/dbc/dbcCriteriaSpecifications.adoc index 1af1561b6f5..6326a215e7f 100644 --- a/src/main/docs/guide/dbc/dbcCriteriaSpecifications.adoc +++ b/src/main/docs/guide/dbc/dbcCriteriaSpecifications.adoc @@ -1,20 +1,14 @@ -In some cases, you need to build a query programmatically and at the runtime; for that, Micronaut Data implements a subset of Jakarta Persistence Criteria API 3.0, which can be used for Micronaut Data JDBC and R2DBC features. To utilize this feature add the following dependency: +Micronaut Criteria API for JDBC / R2DBC currently implements only a subset of the API. -dependency:jakarta.persistence:jakarta.persistence-api[] - -To implement queries that cannot be defined at the compile-time Micronaut Data introduces api:data.repository.JpaSpecificationExecutor[] repository interface that can be used to extend your repository interface: - -snippet::example.PersonRepository[project-base="doc-examples/jdbc-example",source="main" tags="repository",indent="0"] +To use Jakarta Criteria API you need to add an optional dependency: -Each method expects a "specification" which is a functional interface with a set of Criteria API objects intended to build a query programmatically. - -Micronaut Criteria API currently implements only a subset of the API. Most of it is internally used to create queries with predicates and projections. +dependency:jakarta.persistence:jakarta.persistence-api[] Currently, not supported JPA Criteria API features: -- Joins with custom `ON` expressions and typed join methods like `joinSet` etc +- Joins with custom `ON` expressions +- Operators dealing with an entity type and casting - Collection operations: `isMember` etc -- Tuple result type - Transformation expressions like toString, substring etc. - Cases diff --git a/src/main/docs/guide/dbc/dbcCriteriaSpecifications/otherRepositoryVariations.adoc b/src/main/docs/guide/dbc/dbcCriteriaSpecifications/otherRepositoryVariations.adoc deleted file mode 100644 index 646c3033aa4..00000000000 --- a/src/main/docs/guide/dbc/dbcCriteriaSpecifications/otherRepositoryVariations.adoc +++ /dev/null @@ -1,24 +0,0 @@ -Micronaut Data includes different variations of specification executor interface intended to be used with async or reactive repositories. - -.Builtin Variations of `JpaSpecificationExecutor` repository interface -[cols=2*] -|=== -|*Interface* -|*Description* - -|api:data.repository.JpaSpecificationExecutor[] -|The default interface for querying, deleting and updating data - -|api:data.repository.async.AsyncJpaSpecificationExecutor[] -|The async version of the specifications repository - -|api:data.repository.reactive.ReactiveStreamsJpaSpecificationExecutor[] -|The reactive streams - `Publisher<>` version of the specifications repository - -|api:data.repository.reactive.ReactorJpaSpecificationExecutor[] -|The Reactor version of the specifications repository - -|api:data.repository.kotlin.CoroutineJpaSpecificationExecutor[] -|The Kotlin version of the interface that is using coroutines - -|=== \ No newline at end of file diff --git a/src/main/docs/guide/hibernate/hibernateSpecifications.adoc b/src/main/docs/guide/hibernate/hibernateSpecifications.adoc deleted file mode 100644 index a7f42529b88..00000000000 --- a/src/main/docs/guide/hibernate/hibernateSpecifications.adoc +++ /dev/null @@ -1,25 +0,0 @@ -Based on the https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#specifications[same concept as Spring Data], when you need to create queries dynamically by composing JPA criteria then you can implement the api:data.jpa.repository.JpaSpecificationExecutor[] interface which provides multiple methods that receive an instance of api:data.jpa.repository.criteria.Specification[] which can be used in combination with existing repository interfaces. - -The api:data.jpa.repository.criteria.Specification[] interface represents a simple Criteria-based API entry point: - -[source,java] ----- -public interface Specification { - - @Nullable - Predicate toPredicate(@NonNull Root root, - @NonNull CriteriaQuery query, - @NonNull CriteriaBuilder criteriaBuilder); - -} ----- - -The following example implementation demonstrates custom entity filtering using specifications: - -snippet::example.ProductRepository[project-base="doc-examples/hibernate-example", source="main",tags="spec", indent="0"] - -You can create default methods in your repository class and provide dynamic implementation with a combination of multiple specifications: - -snippet::example.ProductRepository[project-base="doc-examples/hibernate-example", source="main",tags="specifications", indent="0"] - -NOTE: In Micronaut Data, the preferred way is to have build-time generated queries. It's recommended to use Criteria-based API only for queries that need to be generated dynamically at the runtime. diff --git a/src/main/docs/guide/mongo/mongoCriteriaSpecifications/mongoOtherRepositoryVariations.adoc b/src/main/docs/guide/mongo/mongoCriteriaSpecifications/mongoOtherRepositoryVariations.adoc index 646c3033aa4..23482732819 100644 --- a/src/main/docs/guide/mongo/mongoCriteriaSpecifications/mongoOtherRepositoryVariations.adoc +++ b/src/main/docs/guide/mongo/mongoCriteriaSpecifications/mongoOtherRepositoryVariations.adoc @@ -6,19 +6,19 @@ Micronaut Data includes different variations of specification executor interface |*Interface* |*Description* -|api:data.repository.JpaSpecificationExecutor[] +|api:data.repository.jpa.JpaSpecificationExecutor[] |The default interface for querying, deleting and updating data -|api:data.repository.async.AsyncJpaSpecificationExecutor[] +|api:data.repository.jpa.async.AsyncJpaSpecificationExecutor[] |The async version of the specifications repository -|api:data.repository.reactive.ReactiveStreamsJpaSpecificationExecutor[] +|api:data.repository.jpa.reactive.ReactiveStreamsJpaSpecificationExecutor[] |The reactive streams - `Publisher<>` version of the specifications repository -|api:data.repository.reactive.ReactorJpaSpecificationExecutor[] +|api:data.repository.jpa.reactive.ReactorJpaSpecificationExecutor[] |The Reactor version of the specifications repository -|api:data.repository.kotlin.CoroutineJpaSpecificationExecutor[] +|api:data.repository.jpa.kotlin.CoroutineJpaSpecificationExecutor[] |The Kotlin version of the interface that is using coroutines -|=== \ No newline at end of file +|=== diff --git a/src/main/docs/guide/shared.adoc b/src/main/docs/guide/shared.adoc index c34beb1e101..3cda08110fc 100644 --- a/src/main/docs/guide/shared.adoc +++ b/src/main/docs/guide/shared.adoc @@ -4,3 +4,4 @@ The following sections describe shared concepts of all Micronaut Data modules: - <> - define a repository method to access your data - <> - data access operations - <> - transactional access support +- <> - using criteria to write queries diff --git a/src/main/docs/guide/shared/criteriaSpecifications.adoc b/src/main/docs/guide/shared/criteriaSpecifications.adoc new file mode 100644 index 00000000000..b054d3e82f9 --- /dev/null +++ b/src/main/docs/guide/shared/criteriaSpecifications.adoc @@ -0,0 +1,7 @@ +In some cases, you need to build a query programmatically and at the runtime; for that, Micronaut Data supports Jakarta Persistence Criteria API 3.0. + +To implement queries that cannot be defined at the compile-time Micronaut Data introduces api:data.repository.JpaSpecificationExecutor[] repository interface that can be used to extend your repository interface: + +snippet::example.PersonRepository[project-base="doc-examples/jdbc-example",source="main" tags="repository",indent="0"] + +Each method expects a "specification" which is a functional interface with a set of Criteria API objects intended to build a query programmatically. diff --git a/src/main/docs/guide/dbc/dbcCriteriaSpecifications/criteriaExecuteDelete.adoc b/src/main/docs/guide/shared/criteriaSpecifications/criteriaExecuteDelete.adoc similarity index 100% rename from src/main/docs/guide/dbc/dbcCriteriaSpecifications/criteriaExecuteDelete.adoc rename to src/main/docs/guide/shared/criteriaSpecifications/criteriaExecuteDelete.adoc diff --git a/src/main/docs/guide/dbc/dbcCriteriaSpecifications/criteriaExecuteQuery.adoc b/src/main/docs/guide/shared/criteriaSpecifications/criteriaExecuteQuery.adoc similarity index 90% rename from src/main/docs/guide/dbc/dbcCriteriaSpecifications/criteriaExecuteQuery.adoc rename to src/main/docs/guide/shared/criteriaSpecifications/criteriaExecuteQuery.adoc index bd28a74af5e..411b1de4175 100644 --- a/src/main/docs/guide/dbc/dbcCriteriaSpecifications/criteriaExecuteQuery.adoc +++ b/src/main/docs/guide/shared/criteriaSpecifications/criteriaExecuteQuery.adoc @@ -65,3 +65,7 @@ snippet::example.PersonRepositorySpec[project-base="doc-examples/jdbc-example",s NOTE: The examples use compile-known values, and in this case, it would be better to create custom repository methods which would come with compile-time generates queries and eliminate runtime overhead. It's recommended to use criteria only for dynamic queries where the query structure is not known at the build-time. +Pagination with JOINS cannot be properly implemented with limiting the results for tabular SQL results, because of that Micronaut Data will execute two queries: + +- 1. Fetching a page of entity IDs +- 2. Fetching a complete entity with JOINed associations diff --git a/src/main/docs/guide/dbc/dbcCriteriaSpecifications/criteriaExecuteUpdate.adoc b/src/main/docs/guide/shared/criteriaSpecifications/criteriaExecuteUpdate.adoc similarity index 100% rename from src/main/docs/guide/dbc/dbcCriteriaSpecifications/criteriaExecuteUpdate.adoc rename to src/main/docs/guide/shared/criteriaSpecifications/criteriaExecuteUpdate.adoc diff --git a/src/main/docs/guide/shared/criteriaSpecifications/otherRepositoryVariations.adoc b/src/main/docs/guide/shared/criteriaSpecifications/otherRepositoryVariations.adoc new file mode 100644 index 00000000000..993502bb2df --- /dev/null +++ b/src/main/docs/guide/shared/criteriaSpecifications/otherRepositoryVariations.adoc @@ -0,0 +1,53 @@ +Micronaut Data includes different variations of specification executor interface intended to be used with async or reactive repositories. + +.Builtin Variations of `JpaSpecificationExecutor` repository interface +[cols=2*] +|=== +|*Interface* +|*Description* + +|api:data.repository.jpa.JpaSpecificationExecutor[] +|The default interface for querying, deleting and updating data + +|api:data.repository.jpa.async.AsyncJpaSpecificationExecutor[] +|The async version of the specifications repository + +|api:data.repository.jpa.reactive.ReactiveStreamsJpaSpecificationExecutor[] +|The reactive streams - `Publisher<>` version of the specifications repository + +|api:data.repository.jpa.reactive.ReactorJpaSpecificationExecutor[] +|The Reactor version of the specifications repository + +|api:data.repository.jpa.kotlin.CoroutineJpaSpecificationExecutor[] +|The Kotlin version of the interface that is using coroutines + +|=== + +.Each variation supports different Criteria specifications +[cols=2*] +|=== +|*Interface* +|*Description* + +|api:data.repository.jpa.criteria.PredicateSpecification[] +|A simple interface that is producing `Predicate` using the `Root` and `CriteriaBuilder` + +|api:data.repository.jpa.criteria.QuerySpecification[] +|The same as `PredicateSpecification` which also includes `CriteriaQuery` + +|api:data.repository.jpa.criteria.DeleteSpecification[] +|The same as `PredicateSpecification` which also includes `CriteriaDelete` + +|api:data.repository.jpa.criteria.UpdateSpecification[] +|The same as `PredicateSpecification` which also includes `CriteriaUpdate` + +|api:data.repository.jpa.criteria.CriteriaQueryBuilder[] +|The builder of `CriteriaQuery` using `CriteriaBuilder` + +|api:data.repository.jpa.criteria.CriteriaUpdateBuilder[] +|The builder of `CriteriaUpdate` using `CriteriaBuilder` + +|api:data.repository.jpa.criteria.CriteriaDeleteBuilder[] +|The builder of `CriteriaDelete` using `CriteriaBuilder` + +|=== diff --git a/src/main/docs/guide/dbc/dbcCriteriaSpecifications/typeSafeJava.adoc b/src/main/docs/guide/shared/criteriaSpecifications/typeSafeJava.adoc similarity index 83% rename from src/main/docs/guide/dbc/dbcCriteriaSpecifications/typeSafeJava.adoc rename to src/main/docs/guide/shared/criteriaSpecifications/typeSafeJava.adoc index 3b3391919e4..0b60a9e5264 100644 --- a/src/main/docs/guide/dbc/dbcCriteriaSpecifications/typeSafeJava.adoc +++ b/src/main/docs/guide/shared/criteriaSpecifications/typeSafeJava.adoc @@ -15,8 +15,6 @@ q.select(customer.get(Customer_.name)) .where(cb.equal(item.get(Item_.product).get(Product_.productType), "printer")); ---- -Note that as of this writing you cannot use Micronaut Data annotations (those found in the io.micronaut.data.annotation package) to generate static JPA metadata, the only supported way is to use Jakarta Persistence annotations (located in the `jakarta.persistence` package) in combination with Hibernate JPA Static Metamodel Generator which will generate the metamodel even if at runtime you do not actually use Hibernate, but instead use Micronaut Data JDBC. - To configure the metamodel generator simply add the following dependency to the annotation processor classpath: dependency:hibernate-jpamodelgen[groupId="org.hibernate.orm", scope="annotationProcessor"] @@ -24,6 +22,8 @@ dependency:hibernate-jpamodelgen[groupId="org.hibernate.orm", scope="annotationP NOTE: The Hibernate 6 version of `hibernate-jpamodelgen-jakarta` is required because prior versions of Hibernate are still using the `javax.persistence` package. For Kotlin, add the dependency in https://docs.micronaut.io/4.4.3/guide/#kaptOrKsp[kapt or ksp scope], and for Groovy add it in compileOnly scope. +NOTE: The generator supports only Jakarta Persistence annotation (located in the `jakarta.persistence` package), it's not possible to use Micronaut Data annotations (those found in the io.micronaut.data.annotation package) to generate static JPA metadata. + And we need to include the generated classes on the Java classpath to have them accessible: Example for Gradle builds: diff --git a/src/main/docs/guide/toc.yml b/src/main/docs/guide/toc.yml index bea0493b0ef..73c76ed6a12 100644 --- a/src/main/docs/guide/toc.yml +++ b/src/main/docs/guide/toc.yml @@ -1,6 +1,6 @@ introduction: title: Introduction - repository: Repository + repository: Repository whatsNew: What's New? breaks: Breaking Changes releaseHistory: Release History @@ -31,6 +31,13 @@ shared: deletes: Deleting timestamps: Entity Timestamps entityEvents: Entity Events + criteriaSpecifications: + title: Repositories with Jakarta Criteria API + criteriaExecuteQuery: Querying + criteriaExecuteUpdate: Updating + criteriaExecuteDelete: Deleting + otherRepositoryVariations: Different repository variations + typeSafeJava: Type-Safe Java queries transactions: title: Transactions programmaticTransactions: Programmatic Transactions @@ -51,7 +58,6 @@ hibernate: hibernateExplicitQueries: Explicit queries hibernateNativeQueries: Native queries hibernateProcedures: Procedures - hibernateSpecifications: JPA specifications hibernateReactive: Micronaut Data Hibernate Reactive dbc: title: Micronaut Data JDBC and R2DBC @@ -73,11 +79,6 @@ dbc: pessimisticLocking: Pessimistic Locking dbcCriteriaSpecifications: title: Repositories with Criteria API - criteriaExecuteQuery: Querying - criteriaExecuteUpdate: Updating - criteriaExecuteDelete: Deleting - otherRepositoryVariations: Other repository variations - typeSafeJava: Type-Safe Java queries sqlMapping: title: Mapping Entities sqlAnnotations: SQL Annotations