I am using Spring 3.3.0
with JPA.
Here is entity:
@Data
@Entity
@EqualsAndHashCode(of = {"id"})
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Table(name = "articles")
public class Article implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotEmpty
@Column(nullable = false, length = 1024)
private String post;
@Column(nullable = false, updatable = false)
private LocalDateTime createdAt;
@Column
private LocalDateTime updatedAt;
Here is a snippet from the controller:
@PutMapping("{id}")
public ResponseEntity<ArticleResponseDTO> update(
@PathVariable("id") Article fromDb,
@Valid @RequestBody Article article
) {
var updated = articlesService.updateArticle(fromDb, article);
return ResponseEntity.ok(ArticleMapper.toDto(updated));
}
And appropriate service method:
@Transactional
public Article updateArticle(Article fromDb, Article article) {
fromDb.setPost(article.getPost());
return fromDb;
}
Retrieving an entity from DB and passing a new one works fine.
In my opinion, when the entity is loaded and modified (setting new value here) at the end session (flush is invoked) dirty check should check the entity state -> find that it is modified -> store new state to DB. With this purpose @Transactional
is added.
However, it doesn't store modified entity in DB. Even though the updated DTO is finally returned.
When using repo.save(fromDb)
it works fine.
What is the reason for this behaviour?
Is it possible to use dirty checking here?
Here is a link to the example: ArticleService.
It is Spring boot app built with Maven and 21 JDK.
The variable name of fromDb
is misleading. fromDb
is passed as a parameter to the endpoint, which makes fromDb
an unmanaged entity, and requires the use of the save
method.
When updating, retrieve the existing entity from the repository, and update that existing (managed) entity. For example:
@Transactional
public Article updateArticle(long articleId, Article source) {
final var target = repository.getReferenceById(articleId);
target.setPost(source.getPost());
return target;
}