I have an entity class that I would like to audit:
@Data // Lombok for getters/setters
@Entity
public class EventEntity {
@Id
private Long id;
@CreatedBy
private String createdId;
private LocalDateTime creationTimestamp; // @CreatedDate or @CreationTimestamp
@LastModifiedBy
private String modifiedId;
private LocalDateTime lastModifiedTimestamp; // @LastModifiedDate or @UpdateTimestamp
// other fields
}
And I have a JpaRepository
for database operations:
public interface EventRepository extends JpaRepository<EventEntity, Long> {
// Empty
}
There are these annotations and I'm not sure which date annotation I should be using:
org.springframework.data.annotation.CreatedBy
org.springframework.data.annotation.CreatedDate
org.hibernate.annotations.CreationTimestamp
org.springframework.data.annotation.LastModifiedBy
org.springframework.data.annotation.LastModifiedDate
org.hibernate.annotations.UpdateTimestamp
For The @CreatedBy
/ @LastModifiedBy
fields I've implemented org.springframework.data.domain.AuditorAware
as per documentation that just returns a constant:
@Component("auditor")
public class CustomAuditorAware implements AuditorAware<String> {
@Override
public Optional<String> getCurrentAuditor() {
return Optional.of("ID");
}
}
And I've enabled JPA Auditing:
@Configuration
@EnableJpaAuditing("auditor")
public class AppConfig {
}
Here how I've tried persisting to the DB:
EventEntity eventEntity = eventRepository.findById("ID") // returns Optional
.orElse(new EventEntity());
eventEntity.setSomeField("New Value");
eventRepository.save(eventEntity);
(Please correct me on the hibernate entity states if I am wrong below)
Situation 1: EventEntity is new
The no args constructor is called and now the eventEntity
is in transient state. The save()
method executes a select
query followed by an update
query, which will error out with this message:
java.sql.BatchUpdateException: Cannot insert the value NULL into column 'CREATED_ID'
Situation 2: EventEntity exists already
The eventEntity
is now in the detached state. The audit fields are already populated. The save()
method executes a update
query, but none of the audit fields are changed.
Ideal Solution
I don't really care about any of the existing data fields, I just want to update if it exists already. So ideally I won't call the findById()
method. I'll create an EventEntity
in the transient state and it will retain the createdId
and creationTimestamp
data. So almost like above:
EventEntity eventEntity = new EventEntity();
eventEntity.setSomeField("New Value");
eventRepository.save(eventEntity);
My Problem
None of the auditing fields are working as I expect it to. How do I get it working?
Which audit date annotations should I be using? The one from Spring JPA or from hibernate? I've tried both sets with no luck. What's the difference between each?
Versions:
- Spring Boot 2.1
- Hibernate 5.3.10.final
Just add the following annotation in the entity class
@EntityListeners(AuditingEntityListener.class)