使用updatable = false更新实体会将该字段设置为空

时间:2017-02-03 11:21:19

标签: hibernate jpa spring-boot

我使用SpringBoot和JPA / Hibernate,我想添加审核。

我创建了一个抽象实体,其中包含以下内容:

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

@LastModifiedDate
@Column(columnDefinition = "DATETIME(3)")
private ZonedDateTime lastModifiedDate;

该应用程序

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

问题:

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

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

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

更新

存储库定义:

public interface ModelRepository extends JpaRepository<Model, Long> {

REST控制器:

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);
}

端点返回的Json包含&#34; createdDate:null&#34;

更新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;
}

为了使这项工作,我还删除了&#34; updatable = false&#34;来自createdDate字段,以防止结果在保存后具有空日期。

我不明白拥有&#34; updatable = false&#34;如果我们必须在之后手动处理它。

3 个答案:

答案 0 :(得分:1)

也许@CreatedDate(org.springframework.data.annotation.CreatedDate)是错误的注释?我的小型spring-boot JPA / Hibernate CRUD服务器在创建日期列上使用注释@CreationTimestamp(org.hibernate.annotations.CreationTimestamp):

@CreationTimestamp
@Column(name = "CREATED_DATE", nullable = false, updatable = false, columnDefinition = "TIMESTAMP")
private Date created;

请求以null创建日期到达。在调用repo.save()方法时,会发生魔法,并且生成的域对象具有非null创建日期。我没有摆弄实体经理,没有同花顺,nada。

我注意到尽管注释了&#34; updatable = false&#34;在列上,更改现有实体上的创建日期值并调用repo.save()方法会保持该更改而不会抱怨。这让我感到惊讶。

答案 1 :(得分:0)

如果我们暂时只考虑简单的Hibernate,那么在映射上指定updatable=false是完全合法的,但显然必须在某处初始化该值,以便Hibernate知道插入时列中放置的值。 / p>

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

但是我注意到你的模型使用了@CreatedDate注释,从我的简短的谷歌搜索看起来是Spring Data公开的并且与Hibernate无关的东西。这对我来说意味着可能没有在这里正确配置。

我从未在Spring数据中使用此功能,但您可以找到另一篇帖子here。也许它可以帮助突出显示您的配置可能已关闭的位置以及@CreatedDate注释未按预期初始化字段的原因。

<强>更新

如果外部源为您提供了您需要在现有实体顶上应用的状态(例如update方法的情况),则首先需要检索实体并相应地覆盖您的输入。< / p>

// 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() );
}

希望有所帮助。

答案 2 :(得分:0)

我能够通过刷新并清除entityManager然后重新选择数据来解决这个问题。

entityManager.flush(); entityManager.clear();