Decide "isNew" logic with invoked method when using "insert" and "update"
Hello!
I would like to ask and clarify a situation about using JdbcAggregateOperations methods which are not referenced in "CrudRepository".
Suppose that we created a new CrudRepository interface and we want to use "insert" and "update" individually.
@NoRepositoryBean
public interface MyRepository<T, ID> extends CrudRepository<T, ID> {
/* MyRepository */
T insert(T instance);
T update(T instance);
}
Corresponding implementation as follows
@Transactional(readOnly = true)
public class MyJdbcRepository<T, ID> implements MyRepository<T, ID> {
...
@Transactional
@Override
public T insert(T instance) {
return entityOperations.insert(instance);
}
@Transactional
@Override
public T update(T instance) {
return entityOperations.update(instance);
}
...
}
Now I will create a simple pojo with Audit specialitiy.
public class Auditing {
@Id
private String id;
private String name;
@CreatedDate
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime lastUpdatedAt;
...
}
Assume we configured annotation based enabling for both repo and auditing. If we run a simple test like this:
@Test
public void shouldAuditTimes() {
Auditing auditing = new Auditing();
auditing.setId(UUID.randomUUID().toString());
auditingRepository.insert(auditing);
...
}
SDR is invoking "RelationalAuditingCallback" and determining isNew from IsNewAwareAuditingHandler. But, this handler behaves like we called "save" method and trying to resolve it from "org.springframework.data.mapping.PersistentEntity#isNew".
As you can see, I am setting "id" of object so resolved behaviour is "modify". But I am inserting (creating) and calling the "insert" method.
IMHO, this resolving mechanism should honor root method (the actual behaviour "insert" or "update") before checking it from PersistenceEntity. What do you think?
Thanks!
Let's take a step back and see what's going on here. The repository declaration defines persistence methods that let the caller define the entity state (new/existing). That's not how Spring Data is designed. The core concept of a repository is to provide an object to Spring Data, and the existing infrastructure will determine whether the entity should exist in the database or should be inserted (isNew).
This consistent design approach explains why IsNewAwareAuditingHandler comes to a different conclusion if you call insert with a provided identifier.
So I do think that the initial bug is the definition of insert and update methods on the repository as that breaks all components that participate in the IsNew mechanism.
I suggest that your entities implement Persistable.isNew() if you want to continue using insert with pre-populated identifiers. There's no chance and no place we could attach which method you've called to.
While it is not really consistent with the repository abstraction, I still think we should make it work.