使用 updatable=false 更新实体将字段设置为 null

Joh*_*n D 5 hibernate jpa spring-boot

我正在使用带有 JPA/Hibernate 的 SpringBoot,我想添加审计。

我创建了一个具有以下内容的抽象实体:

@CreatedDate
@NotNull
@Column(columnDefinition = "DATETIME(3)", updatable = false)
private ZonedDateTime createdDate;

@LastModifiedDate
@Column(columnDefinition = "DATETIME(3)")
private ZonedDateTime lastModifiedDate;
Run Code Online (Sandbox Code Playgroud)

应用程序

我正在开发一个带有简单 CRUD 实体的 RESTful API。我的资源(控制器)在 jpa 存储库上使用 save() 方法进行创建和更新

问题 :

当我在实体上调用 repository.save() 来更新它时,“createdDate”被忽略(这是正常的),但该方法返回的实体将其“createdDate”设置为 null。

然后实体被放入缓存中,下一个 get 也将其 createdDate 值设为 null。

如何在不允许修改字段 createdDate 和使用 JpaCrudRepository 的情况下更新实体?

更新

存储库定义:

public interface ModelRepository extends JpaRepository<Model, Long> {
Run Code Online (Sandbox Code Playgroud)

休息控制器:

public ResponseEntity<Model> createModel(@RequestBody Model model) throws URISyntaxException {
        Model result = modelRepository.save(model);
        return ResponseEntity.created(new URI("/api/v1/models/" + result.getId()))
            .body(result);
}
Run Code Online (Sandbox Code Playgroud)

端点返回的 Json 包含“createdDate: null”

更新 2

为了解决这个问题,我创建了一个这样的服务:

    @Override
    public Model save(Model model) {
        Model result = modelRepository.save(model);
        return result;
    }

    @Override
    public Model update(Long id, Model model) {
        Model existingModel = modelRepository.findOne(id);
        if (existingModel == null) {
            return null;
        }
        // Non updatable fields
        model.setId(id);
        model.setCreatedDate(existingModel.getCreatedDate());
        Model result = modelRepository.save(model);
        return result;
}
Run Code Online (Sandbox Code Playgroud)

为了完成这项工作,我还从 createdDate 字段中删除了“updatable = false”,以防止结果在保存后出现空日期。

如果我们之后必须手动处理它,我不明白使用“可更新=假”的目的。

Nar*_*ros 1

如果我们暂时考虑一下普通的 Hibernate,那么updatable=false在映射上指定是完全合法的,但显然必须在某个地方初始化该值,以便 Hibernate 知道在插入时要在列中放置什么值。

您自己设置值的解决方案正是普通 Hibernate 用户必须做的。

但我注意到你的模型使用了一个@CreatedDate注释,从我简短的谷歌搜索来看,它似乎是 Spring Data 公开的东西,与 Hibernate 无关。对我来说,这意味着这里可能没有正确配置某些内容。

我从未使用过 Spring 数据中的这个,但你可以在这里找到另一篇文章。也许它可以帮助突出显示您的配置可能在哪里关闭以及为什么@CreatedDate注释没有按您的预期初始化该字段。

更新

在外部源向您提供需要在现有实体之上应用的状态(例如您的update方法的情况)的情况下,您首先需要检索该实体并相应地覆盖您的输入。

// Some controller or business method
public Object updateModel(Model input) {
  final Model model = modelRepository.findOne( input.getId() );
  if ( model != null ) {
    // replicate business case fields
    // sometimes this can be done using frameworks like ObjectMapper, etc.
    // this is just a simple case.
    model.setField1( input.getField1() );
    model.setField2( input.getField2() );
    return modelRepository.update( model );
  }
  throw new UnknownObjectException( "No Model found with id: " + input.getId() );
}
Run Code Online (Sandbox Code Playgroud)

希望有帮助。