我正在使用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)
仍然没有填充时间戳。
答案 0 :(得分:6)
在@PrePersist
和@PreUpdate
阶段调用AuditingEntityListener方法。
这意味着它们将在执行插入或更新SQL语句之前被调用。
在Hibernate文档中了解有关JPA事件的更多信息: 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 {
答案 1 :(得分:1)
我的首选解决方案是一组多个注释,以确保测试@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();
答案 2 :(得分:0)
我遇到了类似的问题(Spring Boot 2.2.1和JUnit5),其值为null
。将@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 {
使用参考:
答案 3 :(得分:0)
我有类似的问题,但是我的情况是因为我在测试类上有@Transactional
批注,删除后,一切按预期进行。