Hibernate 使用updateable=false更新实体时,请将字段设置为null

Hibernate 使用updateable=false更新实体时,请将字段设置为null,hibernate,jpa,spring-boot,Hibernate,Jpa,Spring Boot,我将SpringBoot与JPA/Hibernate一起使用,我想添加审计 我创建了一个具有以下内容的抽象实体: @CreatedDate @NotNull @Column(columnDefinition = "DATETIME(3)", updatable = false) private ZonedDateTime createdDate; @LastModifiedDate @Column(columnDefinition = "DATETIME(3)") private ZonedD

我将SpringBoot与JPA/Hibernate一起使用,我想添加审计

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

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

@LastModifiedDate
@Column(columnDefinition = "DATETIME(3)")
private ZonedDateTime lastModifiedDate;
应用程序

我正在开发一个RESTful API,在实体上使用一个简单的CRUD。 我的resourcescontroller正在jpa存储库上使用save方法进行创建和更新

问题是:

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

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

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

更新

存储库定义:

public interface ModelRepository extends JpaRepository<Model, Long> {
为了实现这一点,我还从createdDate字段中删除了updateable=false,以防止保存后的结果具有空日期


我不理解有UpDebug=false的目的,如果我们必须手动处理它。

如果我们只考虑一段时间的Hibernate,那么在映射中指定可更新= false是完全合法的,但是显然,必须在Hibernate的某个地方初始化该值,以知道在插入时在列中放置什么值。 您自己设置值的解决方案正是普通Hibernate用户必须做的事情

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

我从来没有用过Spring数据,但你可以找到另一篇文章。也许它有助于突出显示您的配置可能关闭的位置以及@CreatedDate注释未按预期初始化字段的原因

更新

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

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

希望这会有所帮助。

我可以通过刷新并清除entityManager,然后重新选择数据来解决这个问题

entityManager.flush;
entityManager.clear

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

@CreationTimestamp
@Column(name = "CREATED_DATE", nullable = false, updatable = false, columnDefinition = "TIMESTAMP")
private Date created;
请求到达时的创建日期为空。调用repo.save方法时,神奇的事情发生了,结果域对象具有非空的创建日期。我不会摆弄实体经理,不会有同花顺,娜达


我注意到,尽管在列上有updateable=false的注释,但在现有实体上更改创建的日期值并调用repo.save方法仍然可以毫无怨言地保持更改。这让我很惊讶。

你能展示一下保存实体的代码吗?@CreatedDate在我看来工作得很好。它是一个完全创建的实体(未检索到)与Updateable false(未更新从DB中选择其原始值)的合并。我能理解为什么不这样做,但我真的不知道哪种方法是最好的,人们做什么。检索对象并更新除不可更新字段外的所有字段?或者检索对象并像我的示例中那样强制新对象的不可更新字段?或者最后,在保存之后,通过entityManager刷新实体?您的帖子显示调用save而不是update,因此我感到困惑。我会更新我的答案。JpaRepository上只有save方法,这就是我使用save的原因。但我们同意,通过这样做,我们不能使用updateable=false,因为一旦我们坚持,问题仍然是一样的。如果Updateable设置为false,则该字段将为null。我不想仅仅因为不想更新字段就必须对每个实体和完整映射执行更新方法。审计和只读创建日期这样简单的事情怎么会产生如此多的复杂性,这就是为什么我提到使用控制器或业务方法来处理创建或更新记录的想法。您不必将这个概念推到存储库级别,尽管从技术上讲它是有意义的。调用/updateModel URI时,调用存储库,获取模型,覆盖更改,然后调用存储库的save方法。这会给你带来你想要的结果。
// 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() );
}
@CreationTimestamp
@Column(name = "CREATED_DATE", nullable = false, updatable = false, columnDefinition = "TIMESTAMP")
private Date created;