Skip to content

JPA / Hibernate, duplicate pkey error when updating entity that is a subclass of a base class that uses IdClass for composite primary key #2767

@cuipengfei

Description

@cuipengfei

How to reproduce this issue

https://github.com/cuipengfei/Spikes/tree/master/jpa/ClassIdUpdateIssue

this code can reproduce the issue, just run the main method then the error will happen.

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.

Issue Description

There is a base class like this:

@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 ......
}

Its IdClass is like this:

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

Then it has a subclass:

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

The subclass only adds one additional field, nothing else fancy.

Then when I try to persist an instance of the subclass like this:

        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

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.

The question

What is the root reason of this issue? Is @IdClass not supposed to be used for this scenario?

links

https://stackoverflow.com/questions/75147518/jpa-hibernate-duplicate-pkey-error-when-updating-entity-that-is-a-subclass-of

https://hibernate.atlassian.net/browse/HHH-16054

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions