[[r2dbc.entity-persistence]]
= Persisting Entities

`R2dbcEntityTemplate` is the central entrypoint for Spring Data R2DBC.
It provides direct entity-oriented methods and a more narrow, fluent interface for typical ad-hoc use-cases, such as querying, inserting, updating, and deleting data.

The entry points (`insert()`, `select()`, `update()`, and others) follow a natural naming schema based on the operation to be run.
Moving on from the entry point, the API is designed to offer only context-dependent methods that lead to a terminating method that creates and runs a SQL statement.
Spring Data R2DBC uses a `R2dbcDialect` abstraction to determine bind markers, pagination support and the data types natively supported by the underlying driver.

NOTE: All terminal methods return always a `Publisher` type that represents the desired operation.
The actual statements are sent to the database upon subscription.

[[r2dbc.entityoperations.save-insert]]
== Methods for Inserting and Updating Entities

There are several convenient methods on `R2dbcEntityTemplate` for saving and inserting your objects.
To have more fine-grained control over the conversion process, you can register Spring converters with `R2dbcCustomConversions` -- for example  `Converter<Person, OutboundRow>` and `Converter<Row, Person>`.

The simple case of using the save operation is to save a POJO.
In this case, the table name is determined by name (not fully qualified) of the class.
You may also call the save operation with a specific collection name.
You can use mapping metadata to override the collection in which to store the object.

When inserting or saving, if the `Id` property is not set, the assumption is that its value will be auto-generated by the database.
Consequently, for auto-generation the type of the `Id` property or field in your class must be a `Long`, or `Integer`.

The following example shows how to insert a row and retrieving its contents:

.Inserting and retrieving entities using the `R2dbcEntityTemplate`
[source,java,indent=0]
----
include::example$r2dbc/R2dbcEntityTemplateSnippets.java[tag=insertAndSelect]
----

The following insert and update operations are available:

A similar set of insert operations is also available:

* `Mono<T>` *insert* `(T objectToSave)`: Insert the object to the default table.
* `Mono<T>` *update* `(T objectToSave)`: Insert the object to the default table.

Table names can be customized by using the fluent API.

[[r2dbc.entityoperations.selecting]]
== Selecting Data

The `select(…)` and `selectOne(…)` methods on `R2dbcEntityTemplate` are used to select data from a table.
Both methods take a <<r2dbc.datbaseclient.fluent-api.criteria,`Query`>> object that defines the field projection, the `WHERE` clause, the `ORDER BY` clause and limit/offset pagination.
Limit/offset functionality is transparent to the application regardless of the underlying database.
This functionality is supported by the xref:r2dbc/getting-started.adoc#r2dbc.dialects[`R2dbcDialect` abstraction] to cater for differences between the individual SQL flavors.

.Selecting entities using the `R2dbcEntityTemplate`
[source,java,indent=0]
----
include::example$r2dbc/R2dbcEntityTemplateSnippets.java[tag=select]
----

[[r2dbc.entityoperations.fluent-api]]
== Fluent API

This section explains the fluent API usage.
Consider the following simple query:

[source,java,indent=0]
----
include::example$r2dbc/R2dbcEntityTemplateSnippets.java[tag=simpleSelect]
----

<1> Using `Person` with the `select(…)` method maps tabular results on `Person` result objects.
<2> Fetching `all()` rows returns a `Flux<Person>` without limiting results.

The following example declares a more complex query that specifies the table name by name, a `WHERE` condition, and an `ORDER BY` clause:

[source,java,indent=0]
----
include::example$r2dbc/R2dbcEntityTemplateSnippets.java[tag=fullSelect]
----

<1> Selecting from a table by name returns row results using the given domain type.
<2> The issued query declares a `WHERE` condition on `firstname` and `lastname` columns to filter results.
<3> Results can be ordered by individual column names, resulting in an `ORDER BY` clause.
<4> Selecting the one result fetches only a single row.
This way of consuming rows expects the query to return exactly a single result.
`Mono` emits a `IncorrectResultSizeDataAccessException` if the query yields more than a single result.

TIP: You can directly apply xref:repositories/projections.adoc[Projections] to results by providing the target type via `select(Class<?>)`.

You can switch between retrieving a single entity and retrieving multiple entities through the following terminating methods:

* `first()`: Consume only the first row, returning a `Mono`.
The returned `Mono` completes without emitting an object if the query returns no results.
* `one()`: Consume exactly one row, returning a `Mono`.
The returned `Mono` completes without emitting an object if the query returns no results.
If the query returns more than one row, `Mono` completes exceptionally emitting `IncorrectResultSizeDataAccessException`.
* `all()`: Consume all returned rows returning a `Flux`.
* `count()`: Apply a count projection returning `Mono<Long>`.
* `exists()`: Return whether the query yields any rows by returning `Mono<Boolean>`.

You can use the `select()` entry point to express your `SELECT` queries.
The resulting `SELECT` queries support the commonly used clauses (`WHERE` and `ORDER BY`) and support pagination.
The fluent API style let you chain together multiple methods while having easy-to-understand code.
To improve readability, you can use static imports that let you avoid using the 'new' keyword for creating `Criteria` instances.

[[r2dbc.datbaseclient.fluent-api.criteria]]
=== Methods for the Criteria Class

The `Criteria` class provides the following methods, all of which correspond to SQL operators:

* `Criteria` *and* `(String column)`: Adds a chained `Criteria` with the specified `property` to the current `Criteria` and returns the newly created one.
* `Criteria` *or* `(String column)`: Adds a chained `Criteria` with the specified `property` to the current `Criteria` and returns the newly created one.
* `Criteria` *greaterThan* `(Object o)`: Creates a criterion by using the `>` operator.
* `Criteria` *greaterThanOrEquals* `(Object o)`: Creates a criterion by using the `>=` operator.
* `Criteria` *in* `(Object... o)`: Creates a criterion by using the `IN` operator for a varargs argument.
* `Criteria` *in* `(Collection<?> collection)`: Creates a criterion by using the `IN` operator using a collection.
* `Criteria` *is* `(Object o)`: Creates a criterion by using column matching (`property = value`).
* `Criteria` *isNull* `()`: Creates a criterion by using the `IS NULL` operator.
* `Criteria` *isNotNull* `()`: Creates a criterion by using the `IS NOT NULL` operator.
* `Criteria` *lessThan* `(Object o)`: Creates a criterion by using the `<` operator.
* `Criteria` *lessThanOrEquals* `(Object o)`: Creates a criterion by using the `<=` operator.
* `Criteria` *like* `(Object o)`: Creates a criterion by using the `LIKE` operator without escape character processing.
* `Criteria` *not* `(Object o)`: Creates a criterion by using the `!=` operator.
* `Criteria` *notIn* `(Object... o)`: Creates a criterion by using the `NOT IN` operator for a varargs argument.
* `Criteria` *notIn* `(Collection<?> collection)`: Creates a criterion by using the `NOT IN` operator using a collection.

You can use `Criteria` with `SELECT`, `UPDATE`, and `DELETE` queries.

[[r2dbc.entityoperations.fluent-api.insert]]
== Inserting Data

You can use the `insert()` entry point to insert data.

Consider the following simple typed insert operation:

[source,java,indent=0]
----
include::example$r2dbc/R2dbcEntityTemplateSnippets.java[tag=insert]
----

<1> Using `Person` with the `into(…)` method sets the `INTO` table, based on mapping metadata.
It also prepares the insert statement to accept `Person` objects for inserting.
<2> Provide a scalar `Person` object.
Alternatively, you can supply a `Publisher` to run a stream of `INSERT` statements.
This method extracts all non-`null` values and inserts them.

[[r2dbc.entityoperations.fluent-api.update]]
== Updating Data

You can use the `update()` entry point to update rows.
Updating data starts by specifying the table to update by accepting `Update` specifying assignments.
It also accepts `Query` to create a `WHERE` clause.

Consider the following simple typed update operation:

[source,java]
----
Person modified = …

include::example$r2dbc/R2dbcEntityTemplateSnippets.java[tag=update]
----

<1> Update `Person` objects and apply mapping based on mapping metadata.
<2> Set a different table name by calling the `inTable(…)` method.
<3> Specify a query that translates into a `WHERE` clause.
<4> Apply the `Update` object.
Set in this case `age` to `42` and return the number of affected rows.

[[r2dbc.entityoperations.fluent-api.delete]]
== Deleting Data

You can use the `delete()` entry point to delete rows.
Removing data starts with a specification of the table to delete from and, optionally, accepts a `Criteria` to create a `WHERE` clause.

Consider the following simple insert operation:

[source,java]
----
include::example$r2dbc/R2dbcEntityTemplateSnippets.java[tag=delete]
----

<1> Delete `Person` objects and apply mapping based on mapping metadata.
<2> Set a different table name by calling the `from(…)` method.
<3> Specify a query that translates into a `WHERE` clause.
<4> Apply the delete operation and return the number of affected rows.

[[r2dbc.entity-persistence.saving]]
Using Repositories, saving an entity can be performed with the `ReactiveCrudRepository.save(…)` method.
If the entity is new, this results in an insert for the entity.

If the entity is not new, it gets updated.
Note that whether an instance is new is part of the instance's state.

NOTE: This approach has some obvious downsides.
If only few of the referenced entities have been actually changed, the deletion and insertion is wasteful.
While this process could and probably will be improved, there are certain limitations to what Spring Data R2DBC can offer.
It does not know the previous state of an aggregate.
So any update process always has to take whatever it finds in the database and make sure it converts it to whatever is the state of the entity passed to the save method.

include::partial$id-generation.adoc[]

[[r2dbc.entity-persistence.optimistic-locking]]
== Optimistic Locking

include::partial$optimistic-locking.adoc[]

[source,java]
----
@Table
class Person {

  @Id Long id;
  String firstname;
  String lastname;
  @Version Long version;
}

R2dbcEntityTemplate template = …;

Mono<Person> daenerys = template.insert(new Person("Daenerys"));                      <1>

Person other = template.select(Person.class)
                 .matching(query(where("id").is(daenerys.getId())))
                 .first().block();                                                    <2>

daenerys.setLastname("Targaryen");
template.update(daenerys);                                                            <3>

template.update(other).subscribe(); // emits OptimisticLockingFailureException        <4>
----

<1> Initially insert row. `version` is set to `0`.
<2> Load the just inserted row. `version` is still `0`.
<3> Update the row with `version = 0`.Set the `lastname` and bump `version` to `1`.
<4> Try to update the previously loaded row that still has `version = 0`.The operation fails with an `OptimisticLockingFailureException`, as the current `version` is `1`.
