From fb5d45c0a139c19bd097c480e315b03352ef56b0 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Wed, 9 Oct 2024 08:23:42 +0200 Subject: [PATCH 1/3] Prepare issue branch. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c6dc5a59a0..b7ece27226 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-commons - 3.4.0-SNAPSHOT + 3.4.0-3173-SNAPSHOT Spring Data Core Core Spring concepts underpinning every Spring Data module. From 15ebe4bb5d19845539ea3c400396c348a5a43ac5 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Wed, 9 Oct 2024 10:00:54 +0200 Subject: [PATCH 2/3] Update documentation. Add section on reserved method names within repository interfaces. --- .../pages/repositories/core-concepts.adoc | 5 +++ .../query-keywords-reference.adoc | 14 +++++++++ .../repositories/query-methods-details.adoc | 31 +++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/src/main/antora/modules/ROOT/pages/repositories/core-concepts.adoc b/src/main/antora/modules/ROOT/pages/repositories/core-concepts.adoc index b326df769f..7c56eb55ea 100644 --- a/src/main/antora/modules/ROOT/pages/repositories/core-concepts.adoc +++ b/src/main/antora/modules/ROOT/pages/repositories/core-concepts.adoc @@ -37,6 +37,11 @@ public interface CrudRepository extends Repository { The methods declared in this interface are commonly referred to as CRUD methods. `ListCrudRepository` offers equivalent methods, but they return `List` where the `CrudRepository` methods return an `Iterable`. +[IMPORTANT] +==== +The repository interface implies a few reserved methods like `findById(ID identifier)` that always target the domain types identifier property regardless of its property name. Read more about this in "`xref:repositories/query-methods-details.adoc#repositories.query-methods.reserved-methods[Defining Query Methods]`". +==== + NOTE: We also provide persistence technology-specific abstractions, such as `JpaRepository` or `MongoRepository`. Those interfaces extend `CrudRepository` and expose the capabilities of the underlying persistence technology in addition to the rather generic persistence technology-agnostic interfaces such as `CrudRepository`. diff --git a/src/main/antora/modules/ROOT/pages/repositories/query-keywords-reference.adoc b/src/main/antora/modules/ROOT/pages/repositories/query-keywords-reference.adoc index 8b08388c53..7c47b81188 100644 --- a/src/main/antora/modules/ROOT/pages/repositories/query-keywords-reference.adoc +++ b/src/main/antora/modules/ROOT/pages/repositories/query-keywords-reference.adoc @@ -21,6 +21,20 @@ Consult the store-specific documentation for the exact list of supported keyword |`…Distinct…`| Use a distinct query to return only unique results. Consult the store-specific documentation whether that feature is supported. This keyword can occur in any place of the subject between `find` (and the other keywords) and `by`. |=============== +[[appendix.query.method.reserved]] +== Reserved methods + +The following table lists reserved methods that use predefined functionality which is directly invoked on the backing (store specific) implementation of the repository proxy. See also "`xref:repositories/query-methods-details.adoc#repositories.query-methods.reserved-methods[Defining Query Methods]`". + +.Reserved methods +|=============== +|`deleteAllById(Iterable identifiers)` +|`deleteById(ID identifier)` +|`existsById(ID identifier)` +|`findAllById(Iterable identifiers)` +|`findById(ID identifier)` +|=============== + [[appendix.query.method.predicate]] == Supported query method predicate keywords and modifiers diff --git a/src/main/antora/modules/ROOT/pages/repositories/query-methods-details.adoc b/src/main/antora/modules/ROOT/pages/repositories/query-methods-details.adoc index 72eb51c260..21919dbec5 100644 --- a/src/main/antora/modules/ROOT/pages/repositories/query-methods-details.adoc +++ b/src/main/antora/modules/ROOT/pages/repositories/query-methods-details.adoc @@ -86,6 +86,37 @@ Whether ignoring cases is supported may vary by store, so consult the relevant s - You can apply static ordering by appending an `OrderBy` clause to the query method that references a property and by providing a sorting direction (`Asc` or `Desc`). To create a query method that supports dynamic sorting, see "`xref:repositories/query-methods-details.adoc#repositories.special-parameters[Paging, Iterating Large Results, Sorting & Limiting]`". +[[repositories.query-methods.reserved-methods]] +== Reserved Methods + +While repository methods typically bind to properties by name, there are a few exceptions to this rule when it comes to certain method names targeting the _identifier_ property. Those _reserved methods_ like `CrudRepository#findById` or just `findById` are targeting the _identifier_ property independent of the actual property name used in the declared method. + +Consider the following domain type holding a property `pk` marked as the identifier via `@Id` and a property called `id`. In this case you need to pay close attention to the naming of your lookup methods as they may collide with predefined signatures. + +==== +[source,java] +---- +public class User { + @Id + Long pk; <1> + Long id; <2> + // ... +} + +public interface UserRepository extends Repository { + Optional findById(Long id); <3> + Optional findByPk(Long pk); <4> + Optional findUserById(Long id); <5> +} +---- +<1> The identifier property / primary key. +<2> A property called id, but not the identifying one. +<3> Targets the `User#pk` property (the one marked with `@Id` which is considered to be the identifier) instead of `User#id` as the property name would suggest because it is one of the _reserved methods_. +<4> Targets the `User#pk` property by name. +<5> Targets the `User#id` property by using the descriptive token between `find` and `by` to avoid collisions with _reserved methods_. +==== + +This special behaviour not only targets lookup methods but also applies to the `exits` and `delete` ones. Please refer to the "`xref:repositories/query-keywords-reference.adoc#appendix.query.method.reserved[Repository query keywords]`" for the list of methods. + [[repositories.query-methods.query-property-expressions]] == Property Expressions From 8594893455287cf93663ac42c70fc5a58995d48a Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 10 Oct 2024 11:49:52 +0200 Subject: [PATCH 3/3] Polishing. Add DDD context. Explain identifier to domain object relationship. Tweak wording. --- .../pages/repositories/core-concepts.adoc | 18 +++++++- .../query-keywords-reference.adoc | 4 +- .../repositories/query-methods-details.adoc | 44 ++++++++++++------- 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/src/main/antora/modules/ROOT/pages/repositories/core-concepts.adoc b/src/main/antora/modules/ROOT/pages/repositories/core-concepts.adoc index 7c56eb55ea..1f77b5ee0e 100644 --- a/src/main/antora/modules/ROOT/pages/repositories/core-concepts.adoc +++ b/src/main/antora/modules/ROOT/pages/repositories/core-concepts.adoc @@ -4,6 +4,18 @@ The central interface in the Spring Data repository abstraction is `Repository`. It takes the domain class to manage as well as the identifier type of the domain class as type arguments. This interface acts primarily as a marker interface to capture the types to work with and to help you to discover interfaces that extend this one. + +[TIP] +==== +Spring Data considers domain types to be entities, more specifically aggregates. +So you will see the term "entity" used throughout the documentation that can be interchanged with the term "domain type" or "aggregate". + +As you might have noticed in the introduction it already hinted towards domain-driven concepts. +We consider domain objects in the sense of DDD. +Domain objects have identifiers (otherwise these would be identity-less value objects), and we somehow need to refer to identifiers when working with certain patterns to access data. +Referring to identifiers will become more meaningful as we talk about repositories and query methods. +==== + The {spring-data-commons-javadoc-base}/org/springframework/data/repository/CrudRepository.html[`CrudRepository`] and {spring-data-commons-javadoc-base}/org/springframework/data/repository/ListCrudRepository.html[`ListCrudRepository`] interfaces provide sophisticated CRUD functionality for the entity class that is being managed. [[repositories.repository]] @@ -39,7 +51,11 @@ The methods declared in this interface are commonly referred to as CRUD methods. [IMPORTANT] ==== -The repository interface implies a few reserved methods like `findById(ID identifier)` that always target the domain types identifier property regardless of its property name. Read more about this in "`xref:repositories/query-methods-details.adoc#repositories.query-methods.reserved-methods[Defining Query Methods]`". +The repository interface implies a few reserved methods like `findById(ID identifier)` that target the domain type identifier property regardless of its property name. +Read more about this in "`xref:repositories/query-methods-details.adoc#repositories.query-methods.reserved-methods[Defining Query Methods]`". + +You can annotate your query method with `@Query` to provide a custom query if a property named `Id` doesn't refer to the identifier. +Following that path can easily lead to confusion and is discouraged as you will quickly hit type limits if the `ID` type and the type of your `Id` property deviate. ==== NOTE: We also provide persistence technology-specific abstractions, such as `JpaRepository` or `MongoRepository`. diff --git a/src/main/antora/modules/ROOT/pages/repositories/query-keywords-reference.adoc b/src/main/antora/modules/ROOT/pages/repositories/query-keywords-reference.adoc index 7c47b81188..737b8818d3 100644 --- a/src/main/antora/modules/ROOT/pages/repositories/query-keywords-reference.adoc +++ b/src/main/antora/modules/ROOT/pages/repositories/query-keywords-reference.adoc @@ -24,7 +24,9 @@ Consult the store-specific documentation for the exact list of supported keyword [[appendix.query.method.reserved]] == Reserved methods -The following table lists reserved methods that use predefined functionality which is directly invoked on the backing (store specific) implementation of the repository proxy. See also "`xref:repositories/query-methods-details.adoc#repositories.query-methods.reserved-methods[Defining Query Methods]`". +The following table lists reserved methods that use predefined functionality (as defined in `CrudRepository`). +These methods are directly invoked on the backing (store-specific) implementation of the repository proxy. +See also "`xref:repositories/query-methods-details.adoc#repositories.query-methods.reserved-methods[Defining Query Methods]`". .Reserved methods |=============== diff --git a/src/main/antora/modules/ROOT/pages/repositories/query-methods-details.adoc b/src/main/antora/modules/ROOT/pages/repositories/query-methods-details.adoc index 21919dbec5..8ba270060f 100644 --- a/src/main/antora/modules/ROOT/pages/repositories/query-methods-details.adoc +++ b/src/main/antora/modules/ROOT/pages/repositories/query-methods-details.adoc @@ -87,35 +87,45 @@ Whether ignoring cases is supported may vary by store, so consult the relevant s To create a query method that supports dynamic sorting, see "`xref:repositories/query-methods-details.adoc#repositories.special-parameters[Paging, Iterating Large Results, Sorting & Limiting]`". [[repositories.query-methods.reserved-methods]] -== Reserved Methods +== Reserved Method Names -While repository methods typically bind to properties by name, there are a few exceptions to this rule when it comes to certain method names targeting the _identifier_ property. Those _reserved methods_ like `CrudRepository#findById` or just `findById` are targeting the _identifier_ property independent of the actual property name used in the declared method. + -Consider the following domain type holding a property `pk` marked as the identifier via `@Id` and a property called `id`. In this case you need to pay close attention to the naming of your lookup methods as they may collide with predefined signatures. +While derived repository methods bind to properties by name, there are a few exceptions to this rule when it comes to certain method names inherited from the base repository targeting the _identifier_ property. +Those _reserved methods_ like `CrudRepository#findById` (or just `findById`) are targeting the _identifier_ property regardless of the actual property name used in the declared method. + +Consider the following domain type holding a property `pk` marked as the identifier via `@Id` and a property called `id`. +In this case you need to pay close attention to the naming of your lookup methods as they may collide with predefined signatures: ==== [source,java] ---- -public class User { - @Id - Long pk; <1> - Long id; <2> - // ... +class User { + @Id Long pk; <1> + + Long id; <2> + + // … } -public interface UserRepository extends Repository { - Optional findById(Long id); <3> - Optional findByPk(Long pk); <4> +interface UserRepository extends Repository { + + Optional findById(Long id); <3> + + Optional findByPk(Long pk); <4> + Optional findUserById(Long id); <5> } ---- -<1> The identifier property / primary key. -<2> A property called id, but not the identifying one. -<3> Targets the `User#pk` property (the one marked with `@Id` which is considered to be the identifier) instead of `User#id` as the property name would suggest because it is one of the _reserved methods_. -<4> Targets the `User#pk` property by name. -<5> Targets the `User#id` property by using the descriptive token between `find` and `by` to avoid collisions with _reserved methods_. + +<1> The identifier property (primary key). +<2> A property named `id`, but not the identifier. +<3> Targets the `pk` property (the one marked with `@Id` which is considered to be the identifier) as it refers to a `CrudRepository` base repository method. +Therefore, it is not a derived query using of `id` as the property name would suggest because it is one of the _reserved methods_. +<4> Targets the `pk` property by name as it is a derived query. +<5> Targets the `id` property by using the descriptive token between `find` and `by` to avoid collisions with _reserved methods_. ==== -This special behaviour not only targets lookup methods but also applies to the `exits` and `delete` ones. Please refer to the "`xref:repositories/query-keywords-reference.adoc#appendix.query.method.reserved[Repository query keywords]`" for the list of methods. +This special behaviour not only targets lookup methods but also applies to the `exits` and `delete` ones. +Please refer to the "`xref:repositories/query-keywords-reference.adoc#appendix.query.method.reserved[Repository query keywords]`" for the list of methods. [[repositories.query-methods.query-property-expressions]] == Property Expressions