Search code examples
hibernatemany-to-manyquarkushibernate-mapping

ManyToMany Relationship with composite primary key in Quarkus Hibernate


I am currently building a Quarkus Backend and can't figure out how to map a ManyToMany relationship with additional attributes. Let's say I have a CorporationEntity and an AddressEntity and I want to map those two entities with a ManyToMany relationship and an additional attribute AddressType. I can't really figure out how to do that.

This is what I currently have, but the build crashes due to a mapping error:

GenericEntity.java

@MappedSuperclass
public class GenericEntity extends PanacheEntity {
  public LocalDate createdDate;
  public LocalDate lastRevision;
}

CorporationEntity.java

@Entity
public class CorporationEntity extends GenericEntity {
  @ManyToOne public BuildingEntity airport;
  @ManyToOne public CustomerEntity customer;
  // other attributes...

CorporationHasAddressEntity.java

@Entity
public class CorporationHasAddressEntity extends PanacheEntityBase {
  @EmbeddedId
  CorporationHasAddressKey id;

  @ManyToOne
  @JoinColumn(name = "addressType_id")
  public AddressTypeEntity addressType;
}

CorporationHasAddressKey.java

@Embeddable
public class CorporationHasAddressKey implements Serializable {
  @ManyToOne
  @JoinColumn(name = "corporation_id")
  protected CorporationEntity corporation;

  @ManyToOne
  @JoinColumn(name = "address_id")
  protected AddressEntity address;
}

This is the exception when trying to build:

java.lang.NullPointerException: Cannot invoke "org.hibernate.mapping.PersistentClass.getTable()" because "classMapping" is null

EDIT: If I adjust CorporationHasAddressEntity to extend GenericEntity, then the build succeeds, but the CorporationHasAddressEntity takes the Id of PanacheEntity, which is just an integer.


Solution

  • Actually I found the mistake I made by reading through an article linked by @scrhartley. Link to the article: https://www.baeldung.com/jpa-many-to-many

    In the key class I now just declare Long variables for the ids:

    @Embeddable
    public class CorporationHasAddressKey implements Serializable {
    
      @Column(name = "corporation_id")
      protected Long corporationId;
    
      @Column(name = "address_id")
      protected Long addressId;
    }
    

    Then in the actual Entity I embed the Id, but I also define the ManyToOne:

    @Entity
    public class CorporationHasAddressEntity {
      @EmbeddedId CorporationHasAddressKey id;
    
      @ManyToOne
      @MapsId("corporationId")
      @JoinColumn(name = "corporation_id")
      CorporationEntity corporation;
    
      @ManyToOne
      @MapsId("addressId")
      @JoinColumn(name = "address_id")
      AddressEntity address;
    
      @ManyToOne
      @JoinColumn(name = "addressType_id")
      public AddressTypeEntity addressType;
    }
    

    This seems to work perfectly for me. Thanks again to @scrhartley for the hint.