我在使用@PreUpdate和@PrePersist填充审核字段时遇到问题。例如,当我想更新客户端实体时,字段updatedBy和updatedAt仍为空;即使在调试时,也会执行以@PreUpdate注释的preUpdate()代码。

在AuditingField的代码下面,该代码负责在每个JPA实体中创建/更新审核字段:

@Embeddable
@Getter
@Setter
@NoArgsConstructor
public class FieldAuditing implements Serializable {

    @Column(name = "DATE_CREATION", updatable = false)
    private Instant createdAt;

    @Column(name = "DATE_MODIFICATION", updatable = false)
    private Instant updatedAt;

    @Column(name = "DATE_SUPRESSION", updatable = false)
    private Instant deletedAt;

    @Column(name = "AUTEUR_CREATION", updatable = false, length = 100)
    private String createdBy;

    @Column(name = "AUTEUR_MODIFICATION", updatable = false, length = 100)
    private String updatedBy;

    @Column(name = "AUTEUR_SUPRESSION", updatable = false, length = 100)
    private String deletedBy;

    @Column(name = "IS_SUPPRIMER", nullable = false, updatable = false)
    private boolean isDeleted;

    @PrePersist
    public void prePersist() {
        setCreatedAt(Instant.now());
        setCreatedBy(LoggedInUser.get());
    }

    @PreUpdate
    public void preUpdate() {
        setUpdatedAt(Instant.now());
        setUpdatedBy(LoggedInUser.get());
    }

    @PreRemove
    public void preRemove() {
        setDeletedAt(Instant.now());
        setDeleted(true);
        setDeletedBy(LoggedInUser.get());
    }


}


包含嵌入式审核字段的客户端实体:

@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Table(name="TF_CLIENT", schema="dbo")
public class Client implements Serializable {

    private static final long serialVersionUID = 8832848102370267801L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator="native")
    @GenericGenerator(name = "native", strategy = "native")
    @Column(name = "CLT_ID", nullable = false)
    private Long id;

    @Column(name = "CLT_LIBELLE", nullable = false, length = 50, unique = true)
    private String libelle;

    @Temporal(TemporalType.DATE)
    @Column(name = "CLT_DT_OUVERTURE", nullable = false)
    private Date dateOuverture;

    @Temporal(TemporalType.DATE)
    @Column(name = "CLT_DT_FERMETURE")
    private Date dateFermeture;

    @Column(name = "CLT_B_ACTIF")
    private boolean isActif;

    @Embedded
    private FieldAuditing fieldAuditing = new FieldAuditing() ;

   //... rest of another attributes

}


更新客户端实体的方法

private ClientDto save(ClientDto clientDto, Client client) {
        startDateShouldBeBeforeEndDate(clientDto);
        hasUniqueCodePaies(clientDto.getCodePaies());
        Client clientSaved = clientRepository.save(clientMapper.toEntity(clientDto, client));
        clientMapper.addOrRemoveClientActions(clientDto, clientSaved);
        clientMapper.addOrRemoveClientEtats(clientDto, clientSaved);
        clientRepository.save(clientSaved);
        clientDto.setId(clientSaved.getId());
        return clientDto;
    }


最后是持久化上下文配置:

@Configuration
@PropertySource({"classpath:application.yml"})
@EnableJpaRepositories(
        basePackages = "com.github.maaoutir.clientManager",
        entityManagerFactoryRef = "mainEntityManager")
public class PersistenceContext {

    private final Environment env;

    public PersistenceContext(Environment env) {
        this.env = env;
    }

    @Bean
    @Primary
    public DataSource mainDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(Objects.requireNonNull(env.getProperty("spring.datasource.driverClassName")));
        dataSource.setUrl(env.getProperty("spring.datasource.url"));
        dataSource.setUsername(env.getProperty("spring.datasource.username"));
        dataSource.setPassword(env.getProperty("spring.datasource.password"));
        return dataSource;
    }

    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean mainEntityManager() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(mainDataSource());
        em.setPackagesToScan("com.github.maaoutir.clientManager");

        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        HashMap<String, Object> properties = new HashMap<>();
        // properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
        properties.put("hibernate.dialect", env.getProperty("spring.jpa.hibernate.dialect"));
        em.setJpaPropertyMap(properties);
        return em;
    }

    @Primary
    @Bean
    public PlatformTransactionManager transactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(mainEntityManager().getObject());
        return transactionManager;
    }
}


感谢您的帮助。

最佳答案

您在这些列上使用updatable=false

@Column(name = "DATE_MODIFICATION", updatable = false)
private Instant updatedAt;

@Column(name = "AUTEUR_MODIFICATION", updatable = false, length = 100)
private String updatedBy;


这意味着JPA不会使用此字段来更新列。从updatable的JPA规范中:


该列是否包含在SQL中
持久性生成的UPDATE语句
提供者。


这对于在@PrePersist上设置并在第一个INSERT中保留的createdBycreatedAt列有意义,并且您不希望随后对其进行修改。但是,如果将updatable设置为false,则不会使用UPDATE语句更新@PreUpdate(或@PreRemove)中更新的列。

09-27 07:00