web-dev-qa-db-fra.com

Spring Boot JPA @ CreatedDate @LastModifiedDate non renseigné lors de l'enregistrement de l'objet

J'écris une application avec Spring Boot + JPA, en utilisant une base de données Postgres. J'ai une entité utilisateur et j'essaie d'obtenir un horodatage lorsque l'enregistrement utilisateur est sauvegardé et/ou modifié. Cela ne fonctionne pas. L'enregistrement en cours de sauvegarde a la valeur "null" pour createdDate et lastModifiedDate.

Voici tout le code pertinent dans Kotlin:

@Entity
@Table(name = "app_user")
@EntityListeners(AuditingEntityListener::class)
data class User(
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        @Column(name = "id")
        val id: UUID? = null,

        @NotNull
        @Column(unique = true)
        val email: String,
        val name: String,
        private val password: String,

        @CreatedDate
        @Column(name = "created_date", nullable = false, updatable = false)
        var createdDate: LocalDateTime? = null,

        @LastModifiedDate
        @Column(name = "last_modified_date", nullable = false)
        var lastModifiedDate: LocalDateTime? = null
)

Mes requêtes SQL pour ajouter les champs de date ressemblent à ceci:

ALTER TABLE app_user
ADD COLUMN last_modified_date TIMESTAMP,
ADD COLUMN created_date TIMESTAMP;

J'ai aussi une classe de configuration

@Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorProvider")
class JpaAuditingConfiguration {

    @Bean
    fun auditorProvider(): AuditorAware<String> {
        return AuditorAware { Optional.of(SecurityContextHolder.getContext().authentication.name) }
    }

}

Et ma classe de test:

  @Autowired
    private lateinit var userRepository: UserRepository

    val user = User(
            email = "email",
            name = "name",
            password = "password"
    )

    @Test
    fun `it sets the timestamps when a user is created`() {
        userRepository.save(user)
        user.let {
            assertThat(it.createdDate).isNotNull()
            assertThat(it.lastModifiedDate).isNotNull()
        }
    }

MISE À JOUR:

Il semble que le problème ne survienne que dans les tests. Cela semble bien quand j'exécute le même code pour créer un utilisateur dans l'environnement de développement et non dans les tests.

Ai-je besoin d'une configuration supplémentaire dans les tests?

MISE À JOUR 2

J'ai également essayé d'utiliser le gestionnaire d'entités comme ceci:

@Autowired
lateinit var entityManager: TestEntityManager

Ensuite, dans le test, faites:

entityManager.persist(user)
entityManager.flush()

Et aussi

entityManager.persistAndFlush(user)

Ne remplit toujours pas les horodatages.

5
DArkO

Les méthodes AuditingEntityListener sont appelées dans le @PrePersist et @PreUpdate phase.

Cela signifie qu'elles sont appelées juste avant l'exécution des instructions SQL d'insertion ou de mise à jour.

En savoir plus sur les événements JPA dans le document Hibernate: https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#events-jpa-callbacks

Tests unitaires

Lors de l'utilisation dans les tests, vous devez également activer l'audit sur le test

@DataJpaTest
@RunWith(SpringRunner.class)
@EnableJpaAuditing
public class EntityListenerTest {
10
Simon Martinelli

Ma solution préférée est un ensemble d'annotations multiples pour assurer le test de @CreatedBy ou @CreatedDate:

@RunWith(SpringRunner.class)
@DataJpaTest
@Import(JPAConfig.class)
@WithMockUser(username = "testuser")
public class MYRepositoryTest {
...
}

Mes entités ressemblent à:

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class AbstractEntity {

    @CreatedBy
    private String createdBy;

    @CreatedDate
    private Date createdOn;

    @LastModifiedDate
    private Date updatedOn;

    @LastModifiedBy
    private String updatedBy;
}

Ma configuration JPA est:

@Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorAware")
public class JPAConfig {

    @Bean
    public AuditorAware<String> auditorAware() {
        return () -> Optional.of(((User)     SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername());
    }
}

Maintenant, vos champs d'audit sont également créés lors du test JPA:

assertThat(result.getCreatedBy()).isNotNull().isEqualTo("testuser");
assertThat(result.getCreatedOn()).isNotNull();
assertThat(result.getUpdatedBy()).isNotNull().isEqualTo("testuser");
assertThat(result.getUpdatedOn()).isNotNull();
1
Sma Ma

J'ai eu un problème similaire (Spring Boot 2.2.1 et JUnit5) avec les valeurs null. Ajouter @EnableJpaAuditing pour tester la classe n'a pas fonctionné.

Mon exemple (n'a pas tout copié):

@Getter(AccessLevel.PROTECTED)
@Setter(AccessLevel.PROTECTED)
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class Auditable<U> {

    @CreatedBy
    @Column(name = "created_by", nullable = false)
    private U createdBy;

    @CreatedDate
    @Column(name = "created", nullable = false)
    private OffsetDateTime created;
}

et classe respective:

@Getter
@Setter
@Entity
@Table(name="survey_records")
public class SurveyRecord extends Auditable<String> implements Serializable {

J'avais la configuration suivante pour l'audit:

@Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorProvider", dateTimeProviderRef = "auditingDateTimeProvider")
public class JpaAuditingConfiguration {

    @Bean(name = "auditingDateTimeProvider")
    public DateTimeProvider dateTimeProvider() {
        return () -> Optional.of(OffsetDateTime.now());
    }

    @Bean
    public AuditorAware<String> auditorProvider() {

Obtenir @CreatedBy et @CreatedDate fonctionne uniquement à l'intérieur du test @Import était nécessaire

@DataJpaTest
@Import(JpaAuditingConfiguration.class)
class SurveyRecordRepositoryTest {

Références utilisées:

0
Low