JPA/Hibernate JpaSystemException: identifier of an instance of X was altered from Y to Z

61 Views Asked by At

I'm updating my Spring Boot application from Java 11 to Java 17, and Spring Boot 2.7.18 to 3.2.4, and running the tests I'm getting an error.

So, I have a entity called WorkloadDAO like this:

@Entity
@Table(name = "workloads")
@IdClass(WorkloadId.class)
public class WorkloadDAO {

  @Id
  @NonNull()
  private String id;
  
  @Id
  @Column(name = "created_at", insertable = false, updatable = false, columnDefinition = "TIMESTAMP")
  private LocalDateTime createdAt;

  // more attributes

  @PrePersist
  protected void onCreate() {
    createdAt = LocalDateTime.now();
  }

The createdAt attribute will always be received with null value, and it will be set by the onCreate() method annotated with @PrePersist before save the instance in the database.

As you can see in the annotation @IdClass(WorkloadId.class), I'm setting WorkloadId as the id of this class. The WorkloadId class is like this:

public class WorkloadId implements Serializable {

  private String id;
  private LocalDateTime createdAt;
}

So far, so good until the test. For example, I'm running this test:

  @Test
  void testSaveWorkload() {
    String id = "someid";
    WorkloadDAO dao = WorkloadDAO.builder()
        .id(id)
        .build();

    WorkloadDAO response = repository.saveAndFlush(dao);

    assertThat(repository.findById(WorkloadId.builder()
            .id(id)
            .createdAt(response.getCreatedAt())
            .build()))
        .get()
        .extracting("createdAt").isNotNull();
  }

Before updating Java and Spring Boot, this test was running successfully. But now, I'm getting the following error:

org.springframework.orm.jpa.JpaSystemException: identifier of an instance of com.adevinta.delivery.workloadapi.data.WorkloadDAO was altered from WorkloadId(id=someid, createdAt=2024-03-28T12:26:34.355098) to WorkloadId(id=someid, createdAt=null)

Can you help me to understand why I'm getting this? Thanks!

What I expect to happen is the test works, without setting the field createdAt beforehand.

1

There are 1 best solutions below

7
Lee Greiner On

Your issue is due to the insertable = false attribute on createdAt. The value assigned in @PrePersist will not be saved to the database as a result. Typically 'created at' fields are insertable but not updatable and visa versa for 'modified at' fields. Try changing the createdAt column definition to:

@Column(name = "created_at", insertable = true, updatable = false, columnDefinition = "TIMESTAMP").