title: Is this a correct solution to the Spring Data JDBC problem of the insert/update?
body: <p>PROBLEM:</p>
  <p>when I tried to create a new entity 'Customer' with Spring Data JDBC (in a Spring-boot application)</p>
  <pre><code>@Data
  public class Customer {
      @Id
      private String identifier;
      private String name;
  }
  </code></pre>
  <p>Using a customerRepository:</p>
  <pre><code>@Repository
  public interface CustomerRepository extends CrudRepository&lt;Customer, String&gt; {
  }
  </code></pre>
  <p>For the test so:</p>
  <pre><code>@Test
  public void givenNewCustomer_shouldSaveCustomerInDataBase() {
      //given
      final Customer newCustomer = new Customer();
      newCustomer.setIdentifier(&quot;0002&quot;);
      newCustomer.setName(&quot;juan&quot;);
      //when
      Customer customerSaved = repository.save(newCustomer);
      //then
      then(customerSaved).isNotNull();
  }
  </code></pre>
  <p>I got this error:</p>
  <pre><code>Caused by: org.springframework.dao.IncorrectUpdateSemanticsDataAccessException: Failed to update entity [Customer(identifier=0002, name=juan)]. Id [0002] not found in database.
      at org.springframework.data.jdbc.core.JdbcAggregateChangeExecutionContext.updateWithoutVersion(JdbcAggregateChangeExecutionContext.java:370)
      at org.springframework.data.jdbc.core.JdbcAggregateChangeExecutionContext.executeUpdateRoot(JdbcAggregateChangeExecutionContext.java:115)
      at org.springframework.data.jdbc.core.AggregateChangeExecutor.execute(AggregateChangeExecutor.java:70)
  </code></pre>
  <p>I'm using testcontainer for postgresql data base with this initial script:</p>
  <pre><code>create table customer(
      identifier varchar(30) primary key,
      name varchar(39));
  insert into customer(identifier,name) values ('0001','kevin');
  </code></pre>
  <p>I would like the persistence way to behave like EntityManager.merge () from JPA
  automatically, is there a way to do it? I have one but I don't know if it's the most correct.</p>
  <p>(The full source code (very basic and straightforward) is available <a href="https://github.com/FabianSR/spring_data_jdbc_example" rel="nofollow noreferrer">https://github.com/FabianSR/spring_data_jdbc_example</a>)</p>
  <p>PROPOSED SOLUTION:</p>
  <p>I have implemented a possible solution to this problem, but I don't know if it's the correct way (without using JPA).</p>
  <p>I have made that the Customer class extends a class that implements the Persistable interface, I have implemented its getId () method so that it searches in the Customer fields for the one that is annotated with @Id and returns its value. Also I have added the flag isNew with the default value to true.</p>
  <pre><code>package com.example.model.core;
  
  import lombok.Data;
  import org.springframework.data.annotation.Id;
  import org.springframework.data.annotation.Transient;
  import org.springframework.data.domain.Persistable;
  import java.util.stream.Stream;
  
  @Data
  public abstract class AbstractEntity&lt;I&gt; implements Persistable&lt;I&gt; {
  
      @Transient
      public boolean isNew = true;
  
      @Override
      public I getId() {
          return Stream.of(this.getClass().getDeclaredFields())
                  .filter(field -&gt; field.isAnnotationPresent(Id.class))
                  .map(field -&gt; {
                      field.setAccessible(true);
                      return field;
                  }).findFirst().map(field -&gt;
                  {
                      try {
                          return (I) field.get(this);
                      } catch (IllegalAccessException e) {
                          throw new RuntimeException(e);
                      }
                  }).orElse(null);
      }
  }
  </code></pre>
  <p>And the customer is as follows:</p>
  <pre><code>package com.example.model;
  
  import com.example.model.core.AbstractEntity;
  import lombok.Data;
  import org.springframework.data.annotation.Id;
  
  @Data
  public class Customer extends AbstractEntity&lt;String&gt; {
      @Id
      private String identifier;
      private String name;
  }
  </code></pre>
  <p>Now I have added a new method to the CustomerRepository interface, before saving a Customer, it first searches if it exists, modifies its isNew attribute and saves it (else just saves it)</p>
  <pre><code> package com.example.repository;
  
  import com.example.model.Customer;
  import org.springframework.data.jdbc.repository.query.Modifying;
  import org.springframework.data.repository.CrudRepository;
  import org.springframework.stereotype.Repository;
  
  @Repository
  public interface CustomerRepository extends CrudRepository&lt;Customer, String&gt; {
  
      @Modifying
      default Customer merge(final Customer customer) {
          return this.findById(customer.getId()).map(
                  c -&gt; {
                      customer.setNew(false);
                      return this.save(customer);
                  }
          ).orElse(this.save(customer));
      }
  }
  </code></pre>
  <p>Finally, after changing the tests, calling the new 'merge' method instead of 'save', it already works:</p>
  <pre><code>   @Test
      public void givenNewCustomer_shouldSaveCustomerInDataBase() {
          //given
          final Customer newCustomer = new Customer();
          newCustomer.setIdentifier(&quot;0002&quot;);
          newCustomer.setName(&quot;juan&quot;);
          //when
          Customer customerSaved = repository.merge(newCustomer);
          //then
          then(customerSaved).isNotNull();
      }
  
      @Test
      public void givenOldCustomer_shouldUpdateCustomerInDataBase() {
          //Given
          final Customer oldCustomer = repository.findById(&quot;0001&quot;).orElseThrow(AssertionError::new);
          oldCustomer.setName(oldCustomer.getName() + &quot; hall&quot;);
          //when
          repository.merge(oldCustomer);
          //then
          then(repository.findById(&quot;0001&quot;).map(Customer::getName).map(&quot;kevin hall&quot;::equals).orElse(false)).isTrue();
      }
  </code></pre>
  <p>(Code in branch <a href="https://github.com/FabianSR/spring_data_jdbc_example/tree/proposed_solution" rel="nofollow noreferrer">https://github.com/FabianSR/spring_data_jdbc_example/tree/proposed_solution</a>)</p>
  <p>Is this the best solution or is there a simpler one?</p>