克隆 JPA 实体,包括用 spring 的 createdBy 注释的值

Posted

技术标签:

【中文标题】克隆 JPA 实体,包括用 spring 的 createdBy 注释的值【英文标题】:Cloning JPA entity including value annotated with spring's createdBy 【发布时间】:2019-01-21 04:40:39 【问题描述】:

我有以下超类(抽象)

public abstract class AbstractAuditEntity 
  @CreatedBy
  private String createdBy;

我的数据库中有几个对象。现在我想要一种方法来克隆特定对象及其所有属性,包括 createdBy。我可以将任何 String 设置为此值,但该值会在持久化到数据库之前重置为当前经过身份验证的用户名。

如何防止 spring/jpa 在已填充时覆盖我的 createdBy 字段?

提前致谢!

【问题讨论】:

【参考方案1】:

不幸的是,这似乎是不可能的。

在 AuditingEntityListener 中,@PrePersist 方法如下所示:

@PrePersist
public void touchForCreate(Object target) 

    Assert.notNull(target, "Entity must not be null!");

    if (handler != null) 

        AuditingHandler object = handler.getObject();
        if (object != null) 
            object.markCreated(target);
        
    

然后是 AuditingHandler:

public <T> T markCreated(T source) 

    Assert.notNull(source, "Entity must not be null!");

    return touch(source, true);

由于第二个参数为真,它总是会设置 createdBy 字段:

private Optional<Object> touchAuditor(AuditableBeanWrapper<?> wrapper, boolean isNew) 

    Assert.notNull(wrapper, "AuditableBeanWrapper must not be null!");

    return auditorAware.map(it -> 

        Optional<?> auditor = it.getCurrentAuditor();

        Assert.notNull(auditor,
                () -> String.format("Auditor must not be null! Returned by: %s!", AopUtils.getTargetClass(it)));

        auditor.filter(__ -> isNew).ifPresent(foo -> wrapper.setCreatedBy(foo));
        auditor.filter(__ -> !isNew || modifyOnCreation).ifPresent(foo -> wrapper.setLastModifiedBy(foo));

        return auditor;
    );

但由于这似乎是一个有趣的功能,您应该继续并打开未来的请求: https://jira.spring.io/projects/DATAJPA/issues/DATAJPA-1397?filter=allopenissues

【讨论】:

是的,我看到了 touchAuditor-Method。所以解决这个问题的唯一方法(到目前为止)是在没有 jpa 的情况下将对象直接保存到数据库,对吧?不过,谢谢你的回答! 是的,或者您创建自己的 JPA 侦听器并设置用户。【参考方案2】:

我为 DataJPA 创建了一个功能请求,但我不知道它何时(如果)得到解决。

在此之前,我先保存实体并使用本机 SQL 更改 createdBy。我不会将此标记为已接受的答案。

public interface EntityRepository 
  @Transactional(propagation = NESTED)
  @Modifying
  @Query(value = "UPDATE entity_table SET created_by = ? WHERE id = ?", nativeQuery = true)
  void updateSignalRequestCreatedBy(String createdBy, long signalRequestId);

Source DataJPA-Request

【讨论】:

以上是关于克隆 JPA 实体,包括用 spring 的 createdBy 注释的值的主要内容,如果未能解决你的问题,请参考以下文章

Spring/JPA/persistence 实体属性字段不能是最终的?

Spring Data JPA - “找不到类型的属性”异常

Spring Data JPA:嵌套实体的批量插入

Spring Data JPA 多个实体类表联合视图查询

Spring Data JPA中使用QueryDSL进行查询

spring jpa之实体属性类型转换器AttributeConverter,自定义Converter,通用Converter