I understand by default that the CrudRepository.save
method inserts and updates based on a primary key.
Consider the following entity
@Entity
public class BookEntity {
@Id
@Column(name = "id")
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
@Basic
@Column(name = "isbn", unique = true)
private String isbn;
@Basic
@Column(name = "title")
private String title;
@Basic
@Column(name = "author")
private String author;
@Basic
@Column(name = "publication_date")
private Date publicationDate;
@Basic
@Column(name = "rank")
private Integer rank;
}
Because I can not have books with the same isbn in the table and I don't want to worry about generating ids I normally post the following json to an enpoint
{
"isbn": "10932011",
"title": "harry",
"author": "jk",
"publicationDate": "2018-10-10",
"rank": 1000
}
Which returns the following with an auto generated id
{
"id": 3,
"isbn": "10932011",
"title": "harry",
"author": "jk",
"publicationDate": "2018-10-10T00:00:00.000+0000",
"rank": 1000
}
If I make second call using the same isbn I'll get a constraint error
{
"isbn": "10932011",
"title": "harry",
"author": "jk3",
"publicationDate": "2018-10-10",
"rank": 1000
}
But I would like to in fact update the book with the same isbn and not have to specify the auto generated id in the post json as this is not important to me. Is there a way of doing this without having to add logic to a service class?
CrudRepository save() to Update an Instance We can use the same save() method to update an existing entry in our database.
So if the field is null in the entity to save , it will overwrite its value to null in the existing row.
Each of these defines its own functionality: CrudRepository provides CRUD functions. PagingAndSortingRepository provides methods to do pagination and sort records. JpaRepository provides JPA related methods such as flushing the persistence context and delete records in a batch.
The save operation performs a merge on the underlying EntityManager . This on its own doesn't perform any SQL but just returns a managed version of the entity. If that isn't already loaded into the EntityManager it might do this or it might identify the entity as a new one and make it a managed entity.
You can get the BookEntity
, change it and save it.
Since your isbn
is unique, you can do something like this:
BookEntity book = bookRepository.findByIsbn(isbn);
book.setWhateverFieldYouWant(value);
bookRepository.save(book);.
Or another solution
You can create a method with @Query
annotation in BookRepository
:
@Query("UPDATE BookEntity b SET b.whateverField = :value WHERE b.isbn = :isbn")
void updateBook(@Param("value") String value, @Param("isbn") String isbn);
and call it from service:
bookRepository.updateBook(value, isbn);
Since you are using Hibernate, you can also take a look at the NaturalId API Hibernate provides. In addition to your generated ID you annotate your isbn as a @NaturalId and then use the NaturalId API to retrieve your books.
@Entity
public class BookEntity {
@Id
@Column(name = "id")
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
@NaturalId
@Column(name = "isbn")
private String isbn;
Load example:
BookEntity book = entityManager.unwrap(Session.class)
.bySimpleNaturalId(BookEntity.class)
.load("your isbn goes here");
For further reading on NaturalIds take a look at this article (its sample is with isbns) or this one.
A big plus of NaturalIds is you can benefit of hibernate caching mechanisms.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With