4 changed files with 238 additions and 228 deletions
@ -1 +1,236 @@ |
|||||||
include::{commons}@data-commons::page$repositories/core-extensions.adoc[] |
[[core.extensions]] |
||||||
|
= Spring Data Extensions |
||||||
|
|
||||||
|
This section documents a set of Spring Data extensions that enable Spring Data usage in a variety of contexts. |
||||||
|
Currently, most of the integration is targeted towards Spring MVC. |
||||||
|
|
||||||
|
include::{commons}@data-commons::page$repositories/core-extensions-querydsl.adoc[leveloffset=1] |
||||||
|
|
||||||
|
[[mongodb.repositories.queries.type-safe]] |
||||||
|
=== Type-safe Query Methods with Querydsl |
||||||
|
|
||||||
|
MongoDB repository and its reactive counterpart integrates with the http://www.querydsl.com/[Querydsl] project, which provides a way to perform type-safe queries. |
||||||
|
|
||||||
|
[quote,Querydsl Team] |
||||||
|
Instead of writing queries as inline strings or externalizing them into XML files they are constructed via a fluent API. |
||||||
|
|
||||||
|
It provides the following features: |
||||||
|
|
||||||
|
* Code completion in the IDE (all properties, methods, and operations can be expanded in your favorite Java IDE). |
||||||
|
* Almost no syntactically invalid queries allowed (type-safe on all levels). |
||||||
|
* Domain types and properties can be referenced safely -- no strings involved! |
||||||
|
* Adapts better to refactoring changes in domain types. |
||||||
|
* Incremental query definition is easier. |
||||||
|
|
||||||
|
See the http://www.querydsl.com/static/querydsl/latest/reference/html/[QueryDSL documentation] for how to bootstrap your environment for APT-based code generation using Maven or Ant. |
||||||
|
|
||||||
|
QueryDSL lets you write queries such as the following: |
||||||
|
|
||||||
|
[tabs] |
||||||
|
====== |
||||||
|
Imperative:: |
||||||
|
+ |
||||||
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"] |
||||||
|
---- |
||||||
|
QPerson person = QPerson.person; |
||||||
|
List<Person> result = repository.findAll(person.address.zipCode.eq("C0123")); |
||||||
|
|
||||||
|
Page<Person> page = repository.findAll(person.lastname.contains("a"), |
||||||
|
PageRequest.of(0, 2, Direction.ASC, "lastname")); |
||||||
|
---- |
||||||
|
|
||||||
|
Reactive:: |
||||||
|
+ |
||||||
|
[source,java,indent=0,subs="verbatim,quotes",role="secondary"] |
||||||
|
---- |
||||||
|
QPerson person = QPerson.person; |
||||||
|
|
||||||
|
Flux<Person> result = repository.findAll(person.address.zipCode.eq("C0123")); |
||||||
|
---- |
||||||
|
====== |
||||||
|
|
||||||
|
`QPerson` is a class that is generated by the Java annotation processor. |
||||||
|
See xref:#mongodb.repositories.queries.type-safe.apt[Setting up Annotation Processing] for how to setup Annotation Processing with your Build System. |
||||||
|
It is a `Predicate` that lets you write type-safe queries. |
||||||
|
Notice that there are no strings in the query other than the `C0123` value. |
||||||
|
|
||||||
|
You can use the generated `Predicate` class by using the `QuerydslPredicateExecutor` / `ReactiveQuerydslPredicateExecutor` interface, which the following listing shows: |
||||||
|
|
||||||
|
[tabs] |
||||||
|
====== |
||||||
|
Imperative:: |
||||||
|
+ |
||||||
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"] |
||||||
|
---- |
||||||
|
public interface QuerydslPredicateExecutor<T> { |
||||||
|
|
||||||
|
Optional<T> findOne(Predicate predicate); |
||||||
|
|
||||||
|
List<T> findAll(Predicate predicate); |
||||||
|
|
||||||
|
List<T> findAll(Predicate predicate, Sort sort); |
||||||
|
|
||||||
|
List<T> findAll(Predicate predicate, OrderSpecifier<?>... orders); |
||||||
|
|
||||||
|
Page<T> findAll(Predicate predicate, Pageable pageable); |
||||||
|
|
||||||
|
List<T> findAll(OrderSpecifier<?>... orders); |
||||||
|
|
||||||
|
long count(Predicate predicate); |
||||||
|
|
||||||
|
boolean exists(Predicate predicate); |
||||||
|
|
||||||
|
<S extends T, R> R findBy(Predicate predicate, Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction); |
||||||
|
} |
||||||
|
---- |
||||||
|
|
||||||
|
Reactive:: |
||||||
|
+ |
||||||
|
[source,java,indent=0,subs="verbatim,quotes",role="secondary"] |
||||||
|
---- |
||||||
|
interface ReactiveQuerydslPredicateExecutor<T> { |
||||||
|
|
||||||
|
Mono<T> findOne(Predicate predicate); |
||||||
|
|
||||||
|
Flux<T> findAll(Predicate predicate); |
||||||
|
|
||||||
|
Flux<T> findAll(Predicate predicate, Sort sort); |
||||||
|
|
||||||
|
Flux<T> findAll(Predicate predicate, OrderSpecifier<?>... orders); |
||||||
|
|
||||||
|
Flux<T> findAll(OrderSpecifier<?>... orders); |
||||||
|
|
||||||
|
Mono<Long> count(Predicate predicate); |
||||||
|
|
||||||
|
Mono<Boolean> exists(Predicate predicate); |
||||||
|
|
||||||
|
<S extends T, R, P extends Publisher<R>> P findBy(Predicate predicate, |
||||||
|
Function<FluentQuery.ReactiveFluentQuery<S>, P> queryFunction); |
||||||
|
} |
||||||
|
---- |
||||||
|
====== |
||||||
|
|
||||||
|
To use this in your repository implementation, add it to the list of repository interfaces from which your interface inherits, as the following example shows: |
||||||
|
|
||||||
|
[tabs] |
||||||
|
====== |
||||||
|
Imperative:: |
||||||
|
+ |
||||||
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"] |
||||||
|
---- |
||||||
|
interface PersonRepository extends MongoRepository<Person, String>, QuerydslPredicateExecutor<Person> { |
||||||
|
|
||||||
|
// additional query methods go here |
||||||
|
} |
||||||
|
---- |
||||||
|
|
||||||
|
Reactive:: |
||||||
|
+ |
||||||
|
==== |
||||||
|
[source,java,indent=0,subs="verbatim,quotes",role="secondary"] |
||||||
|
---- |
||||||
|
|
||||||
|
interface PersonRepository extends ReactiveMongoRepository<Person, String>, ReactiveQuerydslPredicateExecutor<Person> { |
||||||
|
|
||||||
|
// additional query methods go here |
||||||
|
} |
||||||
|
---- |
||||||
|
|
||||||
|
NOTE: Please note that joins (DBRef's) are not supported with Reactive MongoDB support. |
||||||
|
==== |
||||||
|
====== |
||||||
|
|
||||||
|
[[mongodb.repositories.queries.type-safe.apt]] |
||||||
|
=== Setting up Annotation Processing |
||||||
|
|
||||||
|
To use Querydsl with Spring Data MongoDB, you need to set up annotation processing in your build system that generates the `Q` classes. |
||||||
|
While you could write the `Q` classes by hand, it is recommended to use the Querydsl annotation processor to generate them for you to keep your `Q` classes in sync with your domain model. |
||||||
|
|
||||||
|
Spring Data MongoDB ships with an annotation processor javadoc:org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor[] that isn't registered by default. |
||||||
|
Typically, annotation processors are registered through Java's service loader via `META-INF/services/javax.annotation.processing.Processor` that also activates these once you have them on the class path. |
||||||
|
Most Spring Data users do not use Querydsl, so it does not make sense to require additional mandatory dependencies for projects that would not benefit from Querydsl. |
||||||
|
Hence, you need to activate annotation processing in your build system. |
||||||
|
|
||||||
|
The following example shows how to set up annotation processing by mentioning dependencies and compiler config changes in Maven and Gradle: |
||||||
|
|
||||||
|
[tabs] |
||||||
|
====== |
||||||
|
Maven:: |
||||||
|
+ |
||||||
|
[source,xml,indent=0,subs="verbatim,quotes",role="primary"] |
||||||
|
---- |
||||||
|
<dependencies> |
||||||
|
<dependency> |
||||||
|
<groupId>com.querydsl</groupId> |
||||||
|
<artifactId>querydsl-mongodb</artifactId> |
||||||
|
<version>${querydslVersion}</version> |
||||||
|
<classifier>jakarta</classifier> |
||||||
|
|
||||||
|
<!-- Recommended: Exclude the mongo-java-driver to avoid version conflicts --> |
||||||
|
<exclusions> |
||||||
|
<exclusion> |
||||||
|
<groupId>org.mongodb</groupId> |
||||||
|
<artifactId>mongo-java-driver</artifactId> |
||||||
|
</exclusion> |
||||||
|
</exclusions> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.querydsl</groupId> |
||||||
|
<artifactId>querydsl-apt</artifactId> |
||||||
|
<version>${querydslVersion}</version> |
||||||
|
<classifier>jakarta</classifier> |
||||||
|
<scope>provided</scope> |
||||||
|
</dependency> |
||||||
|
</dependencies> |
||||||
|
|
||||||
|
<build> |
||||||
|
<plugins> |
||||||
|
<plugin> |
||||||
|
<groupId>org.apache.maven.plugins</groupId> |
||||||
|
<artifactId>maven-compiler-plugin</artifactId> |
||||||
|
<configuration> |
||||||
|
<annotationProcessors> |
||||||
|
<annotationProcessor> |
||||||
|
org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor |
||||||
|
</annotationProcessor> |
||||||
|
</annotationProcessors> |
||||||
|
|
||||||
|
<!-- Recommended: Some IDE's might require this configuration to include generated sources for IDE usage --> |
||||||
|
<generatedTestSourcesDirectory>target/generated-test-sources</generatedTestSourcesDirectory> |
||||||
|
<generatedSourcesDirectory>target/generated-sources</generatedSourcesDirectory> |
||||||
|
</configuration> |
||||||
|
</plugin> |
||||||
|
</plugins> |
||||||
|
</build> |
||||||
|
---- |
||||||
|
|
||||||
|
Gradle:: |
||||||
|
+ |
||||||
|
==== |
||||||
|
[source,groovy,indent=0,subs="verbatim,quotes",role="secondary"] |
||||||
|
---- |
||||||
|
dependencies { |
||||||
|
implementation 'com.querydsl:querydsl-mongodb:${querydslVersion}:jakarta' |
||||||
|
|
||||||
|
annotationProcessor 'com.querydsl:querydsl-apt:${querydslVersion}:jakarta' |
||||||
|
annotationProcessor 'org.springframework.data:spring-data-mongodb' |
||||||
|
|
||||||
|
testAnnotationProcessor 'com.querydsl:querydsl-apt:${querydslVersion}:jakarta' |
||||||
|
testAnnotationProcessor 'org.springframework.data:spring-data-mongodb' |
||||||
|
} |
||||||
|
|
||||||
|
tasks.withType(JavaCompile).configureEach { |
||||||
|
options.compilerArgs += [ |
||||||
|
"-processor", |
||||||
|
"org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor"] |
||||||
|
} |
||||||
|
---- |
||||||
|
==== |
||||||
|
====== |
||||||
|
|
||||||
|
Note that the setup above shows the simplest usage omitting any other options or dependencies that your project might require. |
||||||
|
|
||||||
|
include::{commons}@data-commons::page$repositories/core-extensions-web.adoc[leveloffset=1] |
||||||
|
|
||||||
|
include::{commons}@data-commons::page$repositories/core-extensions-populators.adoc[leveloffset=1] |
||||||
|
|||||||
Loading…
Reference in new issue