h1. # How to reproduce this issue
[ <strike>
https://github.com/cuipengfei/Spikes/tree/master/jpa/ClassIdUpdateIssue |https://github.com/cuipengfei/Spikes/tree/master/jpa/ClassIdUpdateIssue|smart-link] ~~
this code can reproduce the issue, just run the main method then the error will happen. </strike>
https://github.com/gregturn/spring-data-jpa-id-class-issues/tree/main/src/test/java/com/example/demo
Just make sure you have docker installed and run these 👆 unit tests.
The unit test with **EmbeddedId** will be ok.
But the one with **IdClass** will **fail**, while we **expect** it to be **successful**.
h1. Issue Description
There is a base class like this:
{code:java} @Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorFormula("case when vip_number is not null then 'vip' else 'normal' end") @DiscriminatorValue("normal") @IdClass(CustomerPK.class) public class CustomerWithIdClass implements Serializable {
private String firstName; private String lastName;
@Id private Long versionId; @Id private Long unitId;
protected CustomerWithIdClass() { }
// getter and setters ...... }{code}
Its IdClass is like this:
{code:java}@NoArgsConstructor @EqualsAndHashCode @Embeddable public class CustomerPK implements Serializable {
private Long unitId;
private Long versionId;
public void setUnitId(Long unitId) { this.unitId = unitId; }
public void setVersionId(Long versionId) { this.versionId = versionId; } }{code}
Then it has a subclass:
{code:java}@Entity @DiscriminatorValue("vip") public class VipCustomerWithIdClass extends CustomerWithIdClass { private String vipNumber;
public VipCustomerWithIdClass() { }
public VipCustomerWithIdClass(String firstName, String lastName, String vipNumber) { super(firstName, lastName); this.vipNumber = vipNumber; }
public String getVipNumber() { return vipNumber; }
public void setVipNumber(String vipNumber) { this.vipNumber = vipNumber; } } {code}
The subclass only adds one additional field, nothing else fancy.
Then when I try to persist an instance of the subclass like this:
{code:java} CustomerWithIdClass customer = new CustomerWithIdClass("a", "b"); customer.setVersionId(123L); customer.setUnitId(456L);
repository.save(customer);//save object of base class, ok
customer.setFirstName("a2"); repository.save(customer);//modify object of base class and save again, ok
VipCustomerWithIdClass vipCustomer = new VipCustomerWithIdClass("a", "b", "888"); vipCustomer.setVersionId(987L); vipCustomer.setUnitId(654L);
repository.save(vipCustomer);//save object of subclass, ok
vipCustomer.setVipNumber("999"); repository.save(vipCustomer);//modify object of subclass and save again, NOT OK // ↑ THIS FAILS BECAUSE OF PRIMARY KEY CONFLICT. INSERT STATEMENT WAS USED INSTEAD OF UPDATE, WHY? // this failure only happens when: // 1. base class uses IdClass for composite primary key // 2. saving an instance of the subclass for the second time after modification {code}
h1. The Error
Then there will be an *error of duplicate pkey* when I try to save the instance of the *subclass* for the *second time* *after some modification*.
The error seems to be related with the @*IdClass* annotation, because I have tried using @*EmbeddedId* and @*Embeddable* for composite pkey, then the error does not happen.
h1. The question
What is the root reason of this issue? Is @IdClass not supposed to be used for this scenario?
h1. links
[https://stackoverflow.com/questions/75147518/jpa-hibernate-duplicate-pkey-error-when-updating-entity-that-is-a-subclass-of|https://stackoverflow.com/questions/75147518/jpa-hibernate-duplicate-pkey-error-when-updating-entity-that-is-a-subclass-of|smart-link]
[https://github.com/spring-projects/spring-data-jpa/issues/2767|https://github.com/spring-projects/spring-data-jpa/issues/2767|smart-link] |
|