From abdbac576c629755fe487807b7e77bc6989f8f6c Mon Sep 17 00:00:00 2001 From: Nathan Rauh Date: Mon, 18 Sep 2023 16:10:48 -0500 Subject: [PATCH 1/3] Issue #255 define parameter-based methods in spec doc Signed-off-by: Nathan Rauh --- .../exceptions/EntityExistsException.java | 55 +++++++++++ api/src/main/java/module-info.java | 99 ++++++++++++++----- spec/src/main/asciidoc/repository.asciidoc | 91 +++++++++++++++-- 3 files changed, 217 insertions(+), 28 deletions(-) create mode 100644 api/src/main/java/jakarta/data/exceptions/EntityExistsException.java diff --git a/api/src/main/java/jakarta/data/exceptions/EntityExistsException.java b/api/src/main/java/jakarta/data/exceptions/EntityExistsException.java new file mode 100644 index 000000000..7f311195d --- /dev/null +++ b/api/src/main/java/jakarta/data/exceptions/EntityExistsException.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 023 Contributors to the Eclipse Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package jakarta.data.exceptions; + +/** + * Indicates that an entity cannot be inserted into the database + * because an entity with same unique identifier already exists in the database. + */ +public class EntityExistsException extends DataException { + private static final long serialVersionUID = -7275063477464065015L; + + /** + * Constructs a new {@code EntityExistsException} with the specified detail message. + * + * @param message the detail message. + */ + public EntityExistsException(String message) { + super(message); + } + + /** + * Constructs a new {@code EntityExistsException} with the specified detail message and cause. + * + * @param message the detail message. + * @param cause another exception or error that caused this exception. + * Null indicates that no other cause is specified. + */ + public EntityExistsException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new {@code EntityExistsException} with the specified cause. + * + * @param cause the cause. + */ + public EntityExistsException(Throwable cause) { + super(cause); + } +} diff --git a/api/src/main/java/module-info.java b/api/src/main/java/module-info.java index 48fa849e7..3a3bbe797 100644 --- a/api/src/main/java/module-info.java +++ b/api/src/main/java/module-info.java @@ -18,6 +18,8 @@ import jakarta.data.Limit; import jakarta.data.Sort; +import jakarta.data.exceptions.EntityExistsException; +import jakarta.data.exceptions.OptimisticLockingFailureException; import jakarta.data.page.Pageable; import jakarta.data.repository.CrudRepository; import jakarta.data.repository.DataRepository; @@ -179,7 +181,7 @@ * * update * updates an existing entity - * public Product update(Product modifiedProduct); + * public boolean update(Product modifiedProduct); * * *

Repository methods following the Query by Method Name pattern @@ -533,21 +535,13 @@ * Ordered map of Id attribute value to entity * * insert(E) - * E, - *
void, Void + * void, Void * For inserting a single entity. * * insert(E...), *
insert(Iterable<E>) - * void, Void, - *
E[], - *
Iterable<E>, - *
Stream<E>, - *
Collection<E> - *
Collection subtypes - * For inserting multiple entities. - *
Collection subtypes must have a public default constructor - * and support addAll or add + * void, Void + * For inserting multiple entities. * * save(E) * E, @@ -568,23 +562,84 @@ * and support addAll or add * * update(E) - * E, - *
void, Void - * For updating a single entity. + * void, Void + *
boolean, Boolean + * For updating a single entity. + *
A boolean result indicates whether or not the database was updated. * * update(E...), *
update(Iterable<E>) * void, Void, - *
E[], - *
Iterable<E>, - *
Stream<E>, - *
Collection<E> - *
Collection subtypes + *
boolean, Boolean, + *
long, Long, + *
int, Integer, + *
short, Short, + *
Number * For updating multiple entities. - *
Collection subtypes must have a public default constructor - * and support addAll or add + *
A boolean result indicates whether or not the database was updated. + *
A numeric result indicates how many entities were updated in the database. + *
Jakarta Persistence providers limit the maximum to Integer.MAX_VALUE * * + *

Methods with Entity Parameters

+ * + *

You can define insert, update, save, and delete + * methods that accept entity parameters.

+ * + *

Insert Methods

+ * + *

Insert methods must create new entity instances in the database. + * If an entity already exists in the database with the same unique identifier, + * then the insert method raises {@link EntityExistsException}.

+ * + *

Update Methods

+ * + *

Update methods modify existing entities in the database based on the + * unique identifier of the entity parameter. If the entity is versioned + * (for example, with {@code @jakarta.persistence.Version} or by another convention + * from the entity model such as having an attribute named {@code version}), + * then the version must also match. When updates are saved to the database, + * the version is automatically incremented. If a matching entity does not exist + * in the database, no update is made for that entity. + * The absence of a matching entity does not cause an error to be raised.

+ * + *

Save Methods

+ * + *

Save methods are a combination of update and insert + * where entities that are already present in the database are updated + * and entities that are not present in the database are inserted.

+ * + *

The unique identifier is used to determine if an entity exists in the database. + * If the entity exists in the database and the entity is versioned + * (for example, with {@code @jakarta.persistence.Version} or by another convention + * from the entity model such as having an attribute named {@code version}), + * then the version must also match. When updates are saved to the database, + * the version is automatically incremented. If the version does not match, + * the save method raises {@link OptimisticLockingFailureException}.

+ * + *

A save method parameter that supplies multiple entities + * might end up updating some and inserting others in the database.

+ * + *

Generated Values + *
When saving to the database, some entity attributes might be automatically + * generated or automatically incremented in the database. + * To obtain these values, define the return type of the save method to be + * the entity type or a type that is a collection or array of the entity. + * Entities that are returned by save methods include updates that + * were made to the entity. No guarantees are made regarding the state of entity + * instances that are supplied as parameters to the method after the method ends.

+ * + *

Delete Methods

+ * + *

Delete methods remove entities from the database based on the + * unique identifier of the entity parameter value. If the entity is versioned + * (for example, with {@code @jakarta.persistence.Version} or by another convention + * from the entity model such as having an attribute named {@code version}), + * then the version must also match. Other entity attributes do not need to match. + * The the unique identifier of an entity is not found in the database or its + * version does not match, the delete method raises + * {@link OptimisticLockingFailureException}.

+ * *

Parameters to Repository Query Methods

* *

The parameters to the {@code find}, {@code exists}, {@code count}, diff --git a/spec/src/main/asciidoc/repository.asciidoc b/spec/src/main/asciidoc/repository.asciidoc index f065331c4..619b1b966 100644 --- a/spec/src/main/asciidoc/repository.asciidoc +++ b/spec/src/main/asciidoc/repository.asciidoc @@ -162,7 +162,7 @@ A variety of basic types can be used for fields or properties of entity classes. |=== -Every entity in Jakarta Data must have a unique identifier composed of one or more supported basic types. This unique identifier is crucial for distinguishing individual entities in the database. Entity models that are used with Jakarta Data must define a way for developers to specify the unique identifier. Typically this is done with an `@Id` annotation, but other means are permitted, such as `@EmbeddedId` in Jakarta Persistence which defines a compound unique identifier based on an embeddable class, or by naming convention (for example, considering a property to be the unique identifier if is named id or ends in Id). +Every entity in Jakarta Data must have a unique identifier composed of one or more supported basic types. This unique identifier is crucial for distinguishing individual entities in the database. Entity models that are used with Jakarta Data must define a way for developers to specify the unique identifier. Typically this is done with an `@Id` annotation, but other means are permitted, such as `@EmbeddedId` in Jakarta Persistence which defines a compound unique identifier based on an embeddable class, or by naming convention (for example, considering a property to be the unique identifier if it is named id or ends in Id). IMPORTANT: It's important to note that key-value, wide-column, document, and relational databases support Collection specializations and Maps of the basic types. However, these databases may have different serialization processes, impacting performance and causing impedance mismatch. Developers should consider these side effects when working with collections and maps in their entity models. @@ -384,10 +384,11 @@ In instances where a Jakarta Data provider for NoSQL databases encounters a recu === Query Methods -In Jakarta Data, besides finding by an ID, custom queries can be written in two ways: +In Jakarta Data, besides finding by an ID, custom queries can be written in three ways: * `@Query` annotation: Defines a query string in the annotation. -* Query by method name: Defines a query based on naming convention used in the method name. +* Query by Method Name: Defines a query based on naming conventions used in the method name. +* Query by Parameters: Defines a query based on the method parameter names and a method name prefix. WARNING: Due to the variety of data sources, those resources might not work; it varies based on the Jakarta Data implementation and the database engine, which can provide queries on more than a Key or ID or not, such as a Key-value database. @@ -416,7 +417,7 @@ public interface ProductRepository extends CrudRepository { ---- -==== Query by Method +==== Query by Method Name The Query by method mechanism allows for creating query commands by naming convention. @@ -611,7 +612,7 @@ WARNING: Define as a priority following standard Java naming conventions, camel In queries by method name, `Id` is an alias for the entity property that is designated as the id. Entity property names that are used in queries by method name must not contain reserved words. -===== Query Methods Keywords +===== Query by Method Name Keywords The following table lists the query-by-method keywords that must be supported by Jakarta Data providers, except where explicitly indicated for a type of database. @@ -774,7 +775,37 @@ Wildcard characters for patterns are determined by the data access provider. For For relational databases, the logical operator `And` takes precedence over `Or`, meaning that `And` is evaluated on conditions before `Or` when both are specified on the same method. For other database types, the precedence is limited to the capabilities of the database. For example, some graph databases are limited to precedence in traversal order. -=== Special Parameter Handling +==== Query by Parameters + +The Query by Parameters pattern determines the query conditions from the names of the method's parameters that are not of type `Limit`, `Sort`, and `Pageable`. Each query condition is an equality comparison, comparing the parameter value against the value of the entity attribute whose name matches the method parameter name. For embedded attributes, the `_` character is used as the delimiter in the method parameter name. All query conditions are implicitly joined by the `And` operator, such that all must match for an entity to be considered matching. + +A method name prefix, either `find` or `exists` or `count` or `delete`, specifies the type of query to be performed. The remainder of the method name can be any valid characters, except that it must not include the `By` keyword, which is what distinguishes it from Query by Method Name. + +Query by Parameters relies on parameter names that are unavailable at run time unless the developer specifies the `-parameters` compiler option. If the Jakarta Data provider does not process repositories at build time, the developer must specify the compiler option to use Query by Parameters. + +Example repository methods that use Query by Parameters: + +[source,java] +---- +@Repository +public interface ProductRepository extends CrudRepository { + + // Assumes that the Product entity has attributes: yearProduced + List findMadeIn(int yearProduced, Sort... sorts); + + // Assumes that the Product entity has attributes: name, status. + boolean existsWithStatus(String name, Status status); + + // Assumes that the Product entity has attributes: yearProduced + void deleteOutdated(int yearProduced); +} +---- + +After the query condition parameters, Query by Parameters `find` methods can include additional parameters of the types listed in the section "Special Parameter Handling". + +Refer to the Jakarta Data module JavaDoc section on "Return Types for Repository Methods" for a listing of valid return types for Query by Parameters methods. + +==== Special Parameter Handling Jakarta Data also supports particular parameters to define pagination and sorting. @@ -808,6 +839,54 @@ first20 = products.findByNameLike(name, pageable); ---- +=== Methods With Entity Parameters + +Repository methods with a name that begins with one of the prefixes, `insert`, `save`, `update`, `delete`, can have a single entity parameter that is one of the following types, where `E` is the entity type: + +- `E` - the entity type +- `E[]` - an array of the entity type +- `E...` - a variable arguments array of the entity type +- `Iterable` and subtypes of `Iterable` - a collection of multiple entities + +Note: A form of `delete` and `update` can be defined in a different manner under the Query by Parameters and Query by Method Name patterns. In those cases, the method can have multiple parameters, none of which can be the entity type. + +==== Insert Methods + +Insert methods must create new entity instances in the database. If an entity already exists in the database with the same unique identifier, then the `insert` method must raise `EntityExistsException`. + +==== Update Methods + +Update methods modify existing entities in the database based on the unique identifier of the entity parameter. If the entity is versioned (for example, with `@code jakarta.persistence.Version` or by another convention from the entity model such as having an attribute named `version`), then the version must also match. When updates are saved to the database, the version is automatically incremented. If a matching entity does not exist in the database, no update is made for that entity. The absence of a matching entity does not cause an error to be raised. + +==== Save Methods + +Save methods are a combination of `update` and `insert` where entities that are already present in the database are updated and entities that are not present in the database are inserted. + +The unique identifier is used to determine if an entity exists in the database. If the entity exists in the database and the entity is versioned (for example, with `@code jakarta.persistence.Version` or by another convention from the entity model such as having an attribute named `version`), then the version must also match. When updates are saved to the database, the version is automatically incremented. If the version does not match, the `save` method must raise `OptimisticLockingFailureException`. + +A `save` method parameter that supplies multiple entities might end up updating some and inserting others in the database. + +===== Generated Values + +When saving to the database, some entity attributes might be automatically generated or automatically incremented in the database. To obtain these values, the user can define the `save` method to return the entity type or a type that is a collection or array of the entity. Entities that are returned by `save` methods must include updates that were made to the entity. Jakarta Data does not require updating instances of entities that are supplied as parameters to the method. + +Example usage: + +[source,java] +---- +product.setPrice(15.99); +product = products.save(product); +System.out.println("Saved version " + product.getVersion() + " of " + product); +---- + +==== Delete Methods + +Delete methods remove entities from the database based on the unique identifier of the entity parameter value. If the entity is versioned (for example, with `@code jakarta.persistence.Version` or by another convention from the entity model such as having an attribute named `version`), then the version must also match. Other entity attributes do not need to match. The the unique identifier of an entity is not found in the database or its version does not match, the `delete` method must raise `OptimisticLockingFailureException`. + +==== Return Types + +Refer to the Jakarta Data module JavaDoc section on "Return Types for Repository Methods" for a listing of valid return types for methods with entity parameters. + === Precedence of Sort Criteria The specification defines different ways of providing sort criteria on queries. This section discusses how these different mechanisms relate to each other. From ba3a536e5fe6b870ee05df0eabcdebacd36b5cb4 Mon Sep 17 00:00:00 2001 From: Nathan Rauh Date: Tue, 19 Sep 2023 06:43:03 -0500 Subject: [PATCH 2/3] code review issue: save operation is missing from list --- spec/src/main/asciidoc/repository.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/src/main/asciidoc/repository.asciidoc b/spec/src/main/asciidoc/repository.asciidoc index 619b1b966..61f183383 100644 --- a/spec/src/main/asciidoc/repository.asciidoc +++ b/spec/src/main/asciidoc/repository.asciidoc @@ -1058,7 +1058,7 @@ When composing repository methods in Jakarta Data, there are a several different | Otherwise, if the method name contains the `By` keyword, determine the query according to the BNF for Query by Method Name. | Query by method name allows dynamic query generation based on method names and parameters. -| Otherwise, process it as Query by Parameters, determining the query from the supplied parameters and the `insert`, `update`, `delete`, `find`, `count`, or `exists` prefix. +| Otherwise, process it as Query by Parameters, determining the query from the supplied parameters and the `save`, `insert`, `update`, `delete`, `find`, `count`, or `exists` prefix. | Query by parameters constructs queries based on method parameters and prefixes. |=== From a83a9d2677096153d885dea7015819b9743b0f87 Mon Sep 17 00:00:00 2001 From: Nathan Rauh Date: Tue, 19 Sep 2023 16:55:15 -0500 Subject: [PATCH 3/3] Code review comment requiring to take insert and update out of the spec --- .../exceptions/EntityExistsException.java | 55 ------------------ api/src/main/java/module-info.java | 58 +------------------ spec/src/main/asciidoc/repository.asciidoc | 23 +++----- 3 files changed, 11 insertions(+), 125 deletions(-) delete mode 100644 api/src/main/java/jakarta/data/exceptions/EntityExistsException.java diff --git a/api/src/main/java/jakarta/data/exceptions/EntityExistsException.java b/api/src/main/java/jakarta/data/exceptions/EntityExistsException.java deleted file mode 100644 index 7f311195d..000000000 --- a/api/src/main/java/jakarta/data/exceptions/EntityExistsException.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 023 Contributors to the Eclipse Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package jakarta.data.exceptions; - -/** - * Indicates that an entity cannot be inserted into the database - * because an entity with same unique identifier already exists in the database. - */ -public class EntityExistsException extends DataException { - private static final long serialVersionUID = -7275063477464065015L; - - /** - * Constructs a new {@code EntityExistsException} with the specified detail message. - * - * @param message the detail message. - */ - public EntityExistsException(String message) { - super(message); - } - - /** - * Constructs a new {@code EntityExistsException} with the specified detail message and cause. - * - * @param message the detail message. - * @param cause another exception or error that caused this exception. - * Null indicates that no other cause is specified. - */ - public EntityExistsException(String message, Throwable cause) { - super(message, cause); - } - - /** - * Constructs a new {@code EntityExistsException} with the specified cause. - * - * @param cause the cause. - */ - public EntityExistsException(Throwable cause) { - super(cause); - } -} diff --git a/api/src/main/java/module-info.java b/api/src/main/java/module-info.java index 3a3bbe797..028f8d443 100644 --- a/api/src/main/java/module-info.java +++ b/api/src/main/java/module-info.java @@ -18,7 +18,6 @@ import jakarta.data.Limit; import jakarta.data.Sort; -import jakarta.data.exceptions.EntityExistsException; import jakarta.data.exceptions.OptimisticLockingFailureException; import jakarta.data.page.Pageable; import jakarta.data.repository.CrudRepository; @@ -171,17 +170,9 @@ * for delete operations * public void delete(person); * - * insert - * creates new entities - * public void insertNewHires(Collection<Employee> newEmployees); - * * save * update if exists, otherwise insert * Product[] saveAll(Product... products) - * - * update - * updates an existing entity - * public boolean update(Product modifiedProduct); * * *

Repository methods following the Query by Method Name pattern @@ -534,15 +525,6 @@ * LinkedHashMap<K, E> * Ordered map of Id attribute value to entity * - * insert(E) - * void, Void - * For inserting a single entity. - * - * insert(E...), - *
insert(Iterable<E>) - * void, Void - * For inserting multiple entities. - * * save(E) * E, *
void, Void @@ -560,52 +542,16 @@ * For saving multiple entities. *
Collection subtypes must have a public default constructor * and support addAll or add - * - * update(E) - * void, Void - *
boolean, Boolean - * For updating a single entity. - *
A boolean result indicates whether or not the database was updated. - * - * update(E...), - *
update(Iterable<E>) - * void, Void, - *
boolean, Boolean, - *
long, Long, - *
int, Integer, - *
short, Short, - *
Number - * For updating multiple entities. - *
A boolean result indicates whether or not the database was updated. - *
A numeric result indicates how many entities were updated in the database. - *
Jakarta Persistence providers limit the maximum to Integer.MAX_VALUE * * *

Methods with Entity Parameters

* - *

You can define insert, update, save, and delete + *

You can define save and delete * methods that accept entity parameters.

* - *

Insert Methods

- * - *

Insert methods must create new entity instances in the database. - * If an entity already exists in the database with the same unique identifier, - * then the insert method raises {@link EntityExistsException}.

- * - *

Update Methods

- * - *

Update methods modify existing entities in the database based on the - * unique identifier of the entity parameter. If the entity is versioned - * (for example, with {@code @jakarta.persistence.Version} or by another convention - * from the entity model such as having an attribute named {@code version}), - * then the version must also match. When updates are saved to the database, - * the version is automatically incremented. If a matching entity does not exist - * in the database, no update is made for that entity. - * The absence of a matching entity does not cause an error to be raised.

- * *

Save Methods

* - *

Save methods are a combination of update and insert + *

Save methods are a combination of update and insert * where entities that are already present in the database are updated * and entities that are not present in the database are inserted.

* diff --git a/spec/src/main/asciidoc/repository.asciidoc b/spec/src/main/asciidoc/repository.asciidoc index 61f183383..5d223cf27 100644 --- a/spec/src/main/asciidoc/repository.asciidoc +++ b/spec/src/main/asciidoc/repository.asciidoc @@ -44,7 +44,7 @@ Several vital characteristics define repositories: - **Built-In Interfaces:** The Jakarta Data specification provides a set of built-in interfaces from which repositories can inherit. These built-in interfaces offer a convenient way to include a variety of pre-defined methods for common operations. They also declare the entity type to use for methods where the entity type cannot otherwise be inferred. -- **Data Retrieval and Modification:** Repositories facilitate data retrieval and modification operations. This includes querying for persistent instances in the data store, creating new persistent instances in the data store, removing existing persistent instances, and modifying the state of persistent instances. Conventionally, these operations are named insert, delete, and update for modifying operations and find, count, and exists for retrieval operations. +- **Data Retrieval and Modification:** Repositories facilitate data retrieval and modification operations. This includes querying for persistent instances in the data store, creating new persistent instances in the data store, removing existing persistent instances, and modifying the state of persistent instances. Conventionally, these operations are named save and delete for modifying operations and find, count, and exists for retrieval operations. - **Subset of Data:** Repositories may expose only a subset of the full data set available in the data store, providing a focused and controlled access point to the data. @@ -841,26 +841,18 @@ first20 = products.findByNameLike(name, pageable); === Methods With Entity Parameters -Repository methods with a name that begins with one of the prefixes, `insert`, `save`, `update`, `delete`, can have a single entity parameter that is one of the following types, where `E` is the entity type: +Repository methods with a name that begins with one of the prefixes, `save` or `delete`, can have a single entity parameter that is one of the following types, where `E` is the entity type: - `E` - the entity type - `E[]` - an array of the entity type - `E...` - a variable arguments array of the entity type - `Iterable` and subtypes of `Iterable` - a collection of multiple entities -Note: A form of `delete` and `update` can be defined in a different manner under the Query by Parameters and Query by Method Name patterns. In those cases, the method can have multiple parameters, none of which can be the entity type. - -==== Insert Methods - -Insert methods must create new entity instances in the database. If an entity already exists in the database with the same unique identifier, then the `insert` method must raise `EntityExistsException`. - -==== Update Methods - -Update methods modify existing entities in the database based on the unique identifier of the entity parameter. If the entity is versioned (for example, with `@code jakarta.persistence.Version` or by another convention from the entity model such as having an attribute named `version`), then the version must also match. When updates are saved to the database, the version is automatically incremented. If a matching entity does not exist in the database, no update is made for that entity. The absence of a matching entity does not cause an error to be raised. +Note: A form of `delete` can be defined in a different manner under the Query by Parameters and Query by Method Name patterns. In those cases, the method can have multiple parameters, none of which can be the entity type. ==== Save Methods -Save methods are a combination of `update` and `insert` where entities that are already present in the database are updated and entities that are not present in the database are inserted. +Save methods are a combination of update and insert where entities that are already present in the database are updated and entities that are not present in the database are inserted. The unique identifier is used to determine if an entity exists in the database. If the entity exists in the database and the entity is versioned (for example, with `@code jakarta.persistence.Version` or by another convention from the entity model such as having an attribute named `version`), then the version must also match. When updates are saved to the database, the version is automatically incremented. If the version does not match, the `save` method must raise `OptimisticLockingFailureException`. @@ -881,7 +873,7 @@ System.out.println("Saved version " + product.getVersion() + " of " + product); ==== Delete Methods -Delete methods remove entities from the database based on the unique identifier of the entity parameter value. If the entity is versioned (for example, with `@code jakarta.persistence.Version` or by another convention from the entity model such as having an attribute named `version`), then the version must also match. Other entity attributes do not need to match. The the unique identifier of an entity is not found in the database or its version does not match, the `delete` method must raise `OptimisticLockingFailureException`. +Delete methods remove entities from the database based on the unique identifier of the entity parameter value. If the entity is versioned (for example, with `@code jakarta.persistence.Version` or by another convention from the entity model such as having an attribute named `version`), then the version must also match. Other entity attributes do not need to match. The the unique identifier of an entity is not found in the database or its version does not match, a `delete` method with a return type of `void` or `Void` must raise `OptimisticLockingFailureException`. ==== Return Types @@ -1055,10 +1047,13 @@ When composing repository methods in Jakarta Data, there are a several different | Otherwise, if the method is annotated with `@Query`, the query from the annotation is used. | The `@Query` annotation defines a custom query. +| Otherwise, if the method has a single parameter with a type that is the entity type or array, Iterable, or Iterable subclass of the entity type, determine the operation according to the method name prefix, which can be `save` or `delete`. +| Methods with entity parameters define operations on one or more entities. + | Otherwise, if the method name contains the `By` keyword, determine the query according to the BNF for Query by Method Name. | Query by method name allows dynamic query generation based on method names and parameters. -| Otherwise, process it as Query by Parameters, determining the query from the supplied parameters and the `save`, `insert`, `update`, `delete`, `find`, `count`, or `exists` prefix. +| Otherwise, process it as Query by Parameters, determining the query from the supplied parameters and the `delete`, `find`, `count`, or `exists` prefix. | Query by parameters constructs queries based on method parameters and prefixes. |===