web-dev-qa-db-ja.com

オブジェクトを保存するときに、Spring Boot JPA @ CreatedDate @LastModifiedDateが入力されない

Postgresデータベースを使用して、Spring Boot + JPAでアプリを作成しています。ユーザーエンティティがあり、ユーザーレコードが保存および/または変更されたときにタイムスタンプを取得しようとしています。これは機能しません。保存されるレコードには、createdDateとlastModifiedDateの両方に「null」があります。

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
)

日付フィールドを追加する私のSQLクエリは次のようになります。

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

構成クラスもあります

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

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

}

そして私のテストクラス:

  @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()
        }
    }

更新:

問題はテストでのみ発生するようです。同じコードを実行して、テストではなく開発環境でユーザーを作成すると問題ないようです。

テストで追加の構成が必要ですか?

更新2

私もこのようなエンティティマネージャを使用しようとしました:

@Autowired
lateinit var entityManager: TestEntityManager

次に、テストで以下を実行します。

entityManager.persist(user)
entityManager.flush()

そしてまた

entityManager.persistAndFlush(user)

まだタイムスタンプを入力していません。

5
DArkO

AuditingEntityListenerメソッドは、@PrePersistおよび@PreUpdate 段階。

これは、挿入または更新SQLステートメントが実行される直前に呼び出されることを意味します。

JPAイベントの詳細については、Hibernateのドキュメントをご覧ください。 https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#events-jpa-callbacks

単体テスト

テストで使用する場合は、テストでも監査を有効にする必要があります

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

私が好む解決策は、@CreatedByまたは@CreatedDate

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

私のエンティティは次のようになります。

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

    @CreatedBy
    private String createdBy;

    @CreatedDate
    private Date createdOn;

    @LastModifiedDate
    private Date updatedOn;

    @LastModifiedBy
    private String updatedBy;
}

私のJPA構成は次のとおりです。

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

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

これで、JPAテスト中に監査フィールドも作成されます。

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

null値で同様の問題(Spring Boot 2.2.1およびJUnit5)がありました。 @EnableJpaAuditingをテストクラスに追加しても機能しませんでした。

私の例(すべてをコピーしなかった):

@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;
}

およびそれぞれのクラス:

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

監査用に次の構成がありました。

@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() {

@CreatedBy@CreatedDateをテスト内で動作させるには@Importのみが必要でした

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

使用された参照:

0
Low