21

I have a compound Primary Key (IDHOLIDAYPACKAGE, IDHOLIDAYPACKAGEVARIANT) in table HolidayPackageVariant where IDHOLIDAYPACKAGE refers to entity HolidayPackage with a Many to One relationship between HolidayPackageVariant and HolidayPackage.

When I try to do the compund PK mapping in HolidayPackageVariant, I get the following error:

Initial SessionFactory creation failed.org.hibernate.annotations.common.AssertionFailure: Declaring class is not found in the inheritance state hierarchy: org.wah.model.holidaypackage.HolidayPackageVariantPrimaryKey

Can someone please tell me what am I doing wrong here ?

MY POJOs look like this:

HolidayPackageVariant:

@Entity
@Table(name="HOLIDAYPACKAGEVARIANT")
public final class HolidayPackageVariant {

    private HolidayPackageVariantPrimaryKey idCompound;

    @EmbeddedId
    public HolidayPackageVariantPrimaryKey getIdCompound() {
        return idCompound;
    }

    // other code
}

HolidayPackageVariantPrimaryKey

@Embeddable
public final class HolidayPackageVariantPrimaryKey implements Serializable {

    private Integer idHolidayPackageVariant;
    private HolidayPackage holidayPackage;

    public HolidayPackageVariantPrimaryKey(){}

    public HolidayPackageVariantPrimaryKey(int id, HolidayPackage pkg){
        setIdHolidayPackageVariant(id);
        setHolidayPackage(pkg);
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "IDHOLIDAYPACKAGEVARIANT", nullable = false)
    public Integer getIdHolidayPackageVariant() {
        return idHolidayPackageVariant;
    }

    @Id
    @ManyToOne(fetch=FetchType.LAZY, cascade={CascadeType.ALL})
    @JoinColumn(name="IDHOLIDAYPACKAGE", nullable=false)
    public HolidayPackage getHolidayPackage() {
        return holidayPackage;
    }

    // equals and hashCode
}

HolidayPackage

public final class HolidayPackage {
    private Set<HolidayPackageVariant> holidayPackageVariants = new HashSet<HolidayPackageVariant>(0);

    @OneToMany(fetch=FetchType.LAZY, cascade={CascadeType.ALL}, mappedBy = "idCompound.holidayPackage")
    public Set<HolidayPackageVariant> getHolidayPackageVariants() {
        return holidayPackageVariants;
    }

    // other code
}
brainydexter
  • 19,826
  • 28
  • 77
  • 115
  • Hi @brainydexter, Could you please change the correct answer to this question? I had to fix it then come back here and post the answer only to realize it was already there. – coderatchet Jun 30 '17 at 04:10
  • 1
    @coderatchet done. Thanks for pointing it out. Not doing hibernate stuff anymore so this fell off my radar. – brainydexter Jul 06 '17 at 17:55

3 Answers3

84

You shouldn't have the @Id in the EmbeddedId Class. Remove the Id annotation in your HolidayPackageVariantPrimaryKey and it should work fine.

llogan
  • 121,796
  • 28
  • 232
  • 243
Kiran
  • 864
  • 7
  • 3
  • 4
    This fixed my problem too. I think this should be marked as the answer instead of the previous one. – Jalpesh Jan 05 '13 at 06:55
  • But what would I do e.g. if I want a member `private Long id;` in my `@Embedded` to get an auto-value each time I insert an element? This is [what I am just not getting](http://stackoverflow.com/questions/29976363/hibernate-generatedvalue-in-embedded-always-null) ... – Stefan Falk May 01 '15 at 11:39
  • The ```@IdClass``` blabla above is useless. You finally provided the best answer for me, clear and short, it solved my problem. You da real mvp ! (my bad... I created an ```@Embeddable``` class with a copy/paste from an ```@Entity``` class). – Saad Benbouzid Feb 12 '16 at 10:24
  • How can I then model a composite Id that uses other objects inside it and those objects in term will have its Id attribute? – pumpump Jan 13 '17 at 00:51
2

I've fought once with @EmbeddedId, and I've finished achieving the same goal with @IdClass. The difference is, when you use @IdClass, you don't use it in class definition, but you redeclare the same fields (however, I have then direct getters/setters for id fields, which is more comfortable for me).

Here is my example, from project I use to process freely available address database from Polish government institution GUS:

The composite key:

@Embeddable
class GusPowiatPK implements Serializable {
    private static final long serialVersionUID = 1L;
    private Short powiatNr;
    private GusWojewodztwo wojewodztwo;

    @Column(name = "POW_NR")
    public Short getPowiatNr() {
        return powiatNr;
    }

    public void setPowiatNr(Short powiatNr) {
        this.powiatNr = powiatNr;
    }

    @ManyToOne
    @JoinColumn(name = "WOJ_ID")
    public GusWojewodztwo getWojewodztwo() {
        return wojewodztwo;
    }

    public void setWojewodztwo(GusWojewodztwo wojewodztwo) {
        this.wojewodztwo = wojewodztwo;
    }
}

The class using it (county):

@Entity
@Table(name = "POWIAT")
@IdClass(GusPowiatPK.class)
public class GusPowiat {

    private Short powiatNr;
    private GusWojewodztwo wojewodztwo;
    private String nazwa;
    private Date stanNa;
    private boolean powiatMiejski;

    public GusPowiat() {
        super();
    }

    public GusPowiat(Short powiatNr, GusWojewodztwo wojewodztwo) {
        super();
        this.powiatNr = powiatNr;
        this.wojewodztwo = wojewodztwo;
    }

    @Id
    public Short getPowiatNr() {
        return powiatNr;
    }

    public void setPowiatNr(Short powiatNr) {
        this.powiatNr = powiatNr;
    }

    @Id
    public GusWojewodztwo getWojewodztwo() {
        return wojewodztwo;
    }

    public void setWojewodztwo(GusWojewodztwo wojewodztwo) {
        this.wojewodztwo = wojewodztwo;
    }

    @Column(name = "NAZWA", length = 50, nullable = false)
    public String getNazwa() {
        return nazwa;
    }

    public void setNazwa(String nazwa) {
        this.nazwa = nazwa;
    }

    @Temporal(TemporalType.DATE)
    @Column(name = "STAN_NA", nullable = false)
    public Date getStanNa() {
        return stanNa;
    }

    public void setStanNa(Date stanNa) {
        this.stanNa = stanNa;
    }

    @Column(name = "POW_MIEJSKI")
    public boolean isPowiatMiejski() {
        return powiatMiejski;
    }

    public void setPowiatMiejski(boolean powiatMiejski) {
        this.powiatMiejski = powiatMiejski;
    }
}

The class composing composite key (province):

@Entity
@Table(name = "WOJEWODZTWO")
public class GusWojewodztwo {

    private Short id;
    private String nazwa;
    private Date stanNa;

    public GusWojewodztwo() {
        super();
    }

    public GusWojewodztwo(Short id) {
        super();
        this.id = id;
    }

    @Id
    @Column(name = "WOJ_ID")
    public Short getId() {
        return id;
    }

    public void setId(Short id) {
        this.id = id;
    }

    @Column(name = "NAZWA", length = 50, nullable = false)
    public String getNazwa() {
        return nazwa;
    }

    public void setNazwa(String nazwa) {
        this.nazwa = nazwa;
    }

    @Temporal(TemporalType.DATE)
    @Column(name = "STAN_NA", nullable = false)
    public Date getStanNa() {
        return stanNa;
    }

    public void setStanNa(Date stanNa) {
        this.stanNa = stanNa;
    }
}
Danubian Sailor
  • 1
  • 38
  • 145
  • 223
  • I don't get it as to why should one use IdClass since I need to redefine the same fields in the class. I was hoping to make it work with EmbeddedId – brainydexter Mar 29 '12 at 11:47
0

Applied to a persistent field or property of an entity class or mapped superclass to denote a composite primary key that is an embeddable class. The embeddable class must be annotated as Embeddable. There must be only one EmbeddedId annotation and no Id annotation when the EmbeddedId annotation is used.

The AttributeOverride annotation may be used to override the column mappings declared within the embeddable class.

The MapsId annotation may be used in conjunction with the EmbeddedId annotation to specify a derived primary key.

If the entity has a derived primary key, the AttributeOverride annotation may only be used to override those attributes of the embedded id that do not correspond to the relationship to the parent entity.

Ajay Kumar
  • 4,864
  • 1
  • 41
  • 44