admin管理员组

文章数量:1320661

I'm working with a multitenant Spring Boot app using Spring Data JPA and Hibernate. My entity has auditing fields (@CreatedBy, @CreatedDate, @LastModifiedBy, @LastModifiedDate) populated via @EnableJpaAuditing, and they are correctly saved to the database.

However, after calling save() to merge the entity, the returned entity has the auditing fields set to null, even though they are correctly persisted in the database. When I call entityManager.refresh(object), the fields are correctly populated, but I don’t want to query the database again.

Here is my code:

Models:

@Getter
@Setter
@MappedSuperclass
@RequiredArgsConstructor
@Audited(targetAuditMode = NOT_AUDITED)
@EntityListeners(AuditingEntityListener.class)
public class AbstractEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column
    private UUID id;

    @Column(updatable = false)
    @CreatedBy
    private String createdBy;

    @Column(updatable = false)
    @CreatedDate
    private LocalDateTime createdDate;

    @Column
    @LastModifiedBy
    private String lastModifiedBy;

    @Column
    @LastModifiedDate
    private LocalDateTime lastModifiedDate;
}
@Entity
@Getter
@Setter
@Audited
public class SystemConfiguration extends AbstractEntity {

    @Enumerated(EnumType.STRING)
    private SystemConfigurationTypeEnum code;

    @Column
    private String description;

    @Column
    private String value;

    @Column(columnDefinition = "boolean default true")
    private boolean active = true;

    @Version
    @NotAudited
    private Integer version;
}

Repository:

@Repository
public interface SystemConfigurationRepository extends JpaRepository<SystemConfiguration, UUID> {

    Optional<SystemConfiguration> findByCode(SystemConfigurationTypeEnum code);

    void deleteByCode(SystemConfigurationTypeEnum code);

    boolean existsByCode(SystemConfigurationTypeEnum code);
}

PersistenceConfig:

@Configuration
@EnableJpaRepositories(
        basePackages = {"${multitenancy.tenant.repository.packages}"},
        entityManagerFactoryRef = "tenantEntityManagerFactory",
        transactionManagerRef = "tenantTransactionManager"
)
@EnableConfigurationProperties(JpaProperties.class)
public class TenantPersistenceConfig {

    @Autowired
    private ConfigurableListableBeanFactory beanFactory;

    @Autowired
    private JpaProperties jpaProperties;

    @Value("${multitenancy.tenant.entityManager.packages}")
    private String entityPackages;

    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean tenantEntityManagerFactory(
            @Qualifier("dynamicDataSourceBasedMultiTenantConnectionProvider") MultiTenantConnectionProvider connectionProvider,
            @Qualifier("currentTenantIdentifierResolver") CurrentTenantIdentifierResolver tenantResolver) {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setPersistenceUnitName("tenant-persistence-unit");
        em.setPackagesToScan(entityPackages);

        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);

        Map<String, Object> properties = new HashMap<>(this.jpaProperties.getProperties());
        properties.put(BEAN_CONTAINER, new SpringBeanContainer(this.beanFactory));
        properties.put(MULTI_TENANT_CONNECTION_PROVIDER, connectionProvider);
        properties.put(MULTI_TENANT_IDENTIFIER_RESOLVER, tenantResolver);
        properties.put("hibernate.physical_naming_strategy", "system_configurations_service.multitenancy.MyPhysicalNamingStrategy");
        em.setJpaPropertyMap(properties);

        return em;
    }

    @Bean
    @Primary
    public JpaTransactionManager tenantTransactionManager(
            @Qualifier("tenantEntityManagerFactory") EntityManagerFactory emf) {
        JpaTransactionManager tenantTransactionManager = new JpaTransactionManager();
        tenantTransactionManager.setEntityManagerFactory(emf);
        return tenantTransactionManager;
    }

Service method:

    @Override
    public SystemConfigurationDTO update(SystemConfigurationTypeEnum code, SystemConfigurationDTO systemConfigurationDTO) throws Exception {
        log.debug("Request to update System Configuration by code: {}", code);

        repository.findByCode(code).orElseThrow(() -> new GenericException(SERVICE_TYPE_NOT_FOUND, code));

        SystemConfiguration systemConfiguration = repository.save(mapper.toEntity(systemConfigurationDTO));

        return mapper.toDTO(systemConfiguration);
    }

Mapper(Impl are setting all the fields):

@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface SystemConfigurationMapper {

    SystemConfiguration toEntity(SystemConfigurationDTO dto);

    SystemConfiguration toEntity(SystemConfigurationPatchDTO dto);

    SystemConfigurationDTO toDTO(SystemConfiguration entity);

    List<SystemConfigurationDTO> toDTO(List<SystemConfiguration> entityList);
}

Currently Output:

{
    "id": "fdc59f03-27c7-436d-8022-8e28786639d0",
    "createdBy": null,
    "createdDate": null,
    "lastModifiedBy": null,
    "lastModifiedDate": null,
    "code": "data",
    "description": "data",
    "value": "data",
    "active": true,
    "version": 4
}

Expected Output:

{
    "id": "fdc59f03-27c7-436d-8022-8e28786639d0",
    "createdBy": "system",
    "createdDate": "2025-01-16 09:36:39",
    "lastModifiedBy": "anonymousUser",
    "lastModifiedDate": "2025-01-17 15:12:45",
    "code": "data",
    "description": "data",
    "value": "data",
    "active": true,
    "version": 4
}

Ensured @EnableJpaAuditing is configured. Used saveAndFlush(), which populates @LastModifiedBy and @LastModifiedDate, but @CreatedBy and @CreatedDate are still null. The auditing fields are being persisted correctly but aren’t returned in the entity after save(). I want to avoid calling entityManager.refresh() and get all auditing fields populated without an additional database query. How can I achieve this?

本文标签: