10

How to JPA-declare a composite key with Quarkus?

Trying to use multiple @Id annotations in an @Entity class with Quarkus, results in the error:

Currently the @Id annotation can only be placed on a single field or method. Offending class is abc.model.Property
    at io.quarkus.spring.data.deployment.generate.StockMethodsAdder.getIdAnnotationTargetRec(StockMethodsAdder.java:940)

But first, after declaring

interface PropertyRepository : CrudRepository<Property, Pair<String, abc.model.Entity>>

Without the declaration above, there are no complaints, but no possibility to actively manage instances of Property.

How to circumvent this error?

I'm dealing with two JPA Entities:
1. the first one named Entity (don't mistake for the annotation)
2. the second one named Property

An Entity can have 0..n instances of Property. The code is as follows:

@Entity
data class Entity (
        @Id
        @Column(name = "entity_id", updatable = false)
        var entityId: String? = null,

        @Column(nullable = true)
        var type: String? = null
) {
    @OneToMany(mappedBy = "entity")
    var properties: List<Property>? = null
}
@Entity
data class Property (
        @Id
        @Column(name = "type")
        var type: String? = null,

        @Id
        @ManyToOne
        @JoinColumn(name = "entity_id")
        private var entity: abc.model.Entity? = null
) : Serializable

Declaring the composite primary key as an @EmbeddedId as follows, does not solve the problem, as Quarkus currently doesn't allow other annotations than @Id in this case:

@Entity
data class Entity (
        @Id
        @Column(name = "entity_id", updatable = false)
        var entityId: String? = null,

        @Column(nullable = true)
        var type: String? = null
) {
    @OneToMany(mappedBy = "propertyId.entityId")
    var properties: List<Property>? = null
}

interface PropertyRepository : CrudRepository<Property, PropertyId>

@Embeddable
data class PropertyId (
        var type: String? = null,

        @Column(name = "entity_id")
        private var entityId: String? = null
) : Serializable

@Entity
data class Property (
        @EmbeddedId
        var propertyId: PropertyId? = null,

        @Column(name = "constant_value")
        var constantValue: String? = null
)
java.lang.IllegalArgumentException: Currently only Entities with the @Id annotation are supported. Offending class is abc.model.Property
    at io.quarkus.spring.data.deployment.generate.StockMethodsAdder.getIdAnnotationTargetRec(StockMethodsAdder.java:932)
Min-Soo Pipefeet
  • 2,208
  • 4
  • 12
  • 31

3 Answers3

8

it is possible, your entity must extend PanacheEntityBase and use class level annotation @Table,@Entity,@IdClass(PK.class), where Pk is a POJO with fields of the composite primary key, then you have to declare the same fields with @Id annotation in your entity. eg:

@Entity()
@Table(name = "agent")
@IdClass(AgentPK.class)
public class AgentBRA extends PanacheEntityBase {

   @Id
   public Integer idUsuario;
   @Id
   public Integer idAgent;

and AgentPk:

public class AgentPK implements Serializable{

   protected Integer idUsuario;

   protected Integer idAgent;
   // getters setters and hascode and equals methods
  
  • This could well be a solution for the Hibernate ORM Panache provider. However, the problem (at least in my case, which is similar to the OP's) is with the Quarkus Spring Data JPA extension. – nkmuturi Apr 09 '23 at 10:05
  • Sure, the solution provided was for the first versions of quarkus where the hibernate extension was still experimental. At that time it was more stable and well documented using panache – Salvatore Pannozzo Capodiferro Apr 10 '23 at 11:18
1

If you want to use a repository with a composite key, do not use the Id annotation

            @Getter
            @Setter
            @NoArgsConstructor
            @AllArgsConstructor
            @ToString
            @Entity
            @Table(schema = "dbo", name = "PERSON")
            public class Person  extends PanacheEntityBase {
                
                
                @GeneratedValue(strategy = GenerationType.IDENTITY)
                @Column(name = "ID", unique = true, nullable = false, insertable = false)
                private Integer id;
                
                @EmbeddedId
                private PersonId personId;
             
                @Column(name = "ADDRESS")
                private String address;
                
                @Column(name = "EMAIL")
                private String email;
                
                @Column(name = "PHONE_NUMBER")
                private String phoneNumber;
                
                
                @Getter
                @Setter
                @NoArgsConstructor
                @AllArgsConstructor
                @ToString
                @Embeddable
                public static class PersonId implements Serializable {

                    @Column(name = "FIRST_NAME")
                    private String firstName;

                    @Column(name = "LAST_NAME")
                    private String lastName;

                    @Column(name = "DATE_OF_BIRTH")
                    private String dateOfBirth;

                }
            }

Repository

            public interface PersonRepository extends CrudRepository<Person, Person.PersonId> {
            }
RED-ONE
  • 167
  • 1
  • 5
1

For Quarkus Spring Data JPA, the solution is to switch from using @IdClass to @Embeddable, which is supported by the extension, contrary to OP's comment that "Quarkus currently doesn't allow other annotations than @Id" (that is if OP is using this extension, rather than Panache, which is not quite clear).

Simply annotate the primary key class with "@Embeddable":

@Embeddable
public class FooPK implements Serializable {

    @Column(name = "fooId")
    private String fooId;

    @Column(name = "barId")
    private String barId;
    ...

Then use "@EmbeddedId" in the entity class (replacing the traditional multiple @Id definitions used with @IdClass method):

public class Foo implements Serializable {

    @EmbeddedId
    protected FooPK id;
    ...
nkmuturi
  • 248
  • 3
  • 10