Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Composite Key in JPA / Hibernate with inherited class

i have a composite id defined on my class structure as below. Unfortunatly i always get a hibernate error that complains on the not found "part2":

"Property of @IdClass not found in entity MoreClass : part2"

Can anybody help me on fixing the problem? (or at least point me on a helpful jpa/hibernate doc?)

@IdClass(ClassKey.class)
@Entity
public class MoreClass extends LessClass implements Serializable
{
  @Id
  String part1;
}

@MappedSuperclass
public class LessClass implements Serializable
{
   @Id
   String part2;
}

public class ClassKey implements Serializable
{
   String part1;
   String part2;
}
like image 869
austrianuser Avatar asked Nov 18 '10 14:11

austrianuser


People also ask

How do you achieve composite key in JPA with Hibernate?

In JPA, we have two options to define the composite keys: the @IdClass and @EmbeddedId annotations. In order to define the composite primary keys, we should follow some rules: The composite primary key class must be public. It must have a no-arg constructor.

How does Hibernate handle composite keys?

The following rules apply for composite primary keys: The primary key class must be public and must have a public no-arg constructor. If property-based access is used, the properties of the primary key class must be public or protected. The primary key class must be serializable .

How do you mention a composite key in an entity class?

There are two options to do this: The first approach – is to use the @Embeddable class, which contains all fields representing a composite key. We should create a field in the JPA entity of this type and annotate it with @EmbeddedId . Another option for composite key mapping - @IdClass .

What is @ID annotation in JPA?

In JPA the object id is defined through the @Id annotation and should correspond to the primary key of the object's table. An object id can either be a natural id or a generated id. A natural id is one that occurs in the object and has some meaning in the application.


1 Answers

The mentioned workaround for HHH-9114 bug by Michael works, e.g. in my case by adding to TwitterListedCount : (note that both @Id and @Type must be added for user types to still work)

// TODO: https://hibernate.atlassian.net/browse/HHH-9114
@Override @Id
public long getTwitterUserId() {
    return super.getTwitterUserId();
}

@Override @Id
public DateTime getFetchTime() {
    return super.getFetchTime();
}

BTW, the workaround has a nasty side-effect HHH-9350 when used with schema generation, it generates duplicate composite columns:

CREATE TABLE buzz.twitterlistedcount
(
  id_fetchtime timestamp without time zone NOT NULL,
  id_twitteruserid bigint NOT NULL,
  _identifiermapper_fetchtime timestamp without time zone NOT NULL,
  _identifiermapper_twitteruserid bigint NOT NULL,
  listedcount integer NOT NULL,
  CONSTRAINT twitterlistedcount_pkey PRIMARY KEY (id_fetchtime, id_twitteruserid)
)
WITH (
  OIDS=FALSE
);

I tried to not use @MappedSuperclass at all, but the wrong schema generation still happens. BTW I'm using DefaultComponentSafeNamingStrategy which may be where the bug lies. This is probably a different bug, asked in Hibernate find with composite key. Invalid column name Exception

The proper workaround involves adding @Column(name=) manually, which works well with schema generation:

@Id
@Basic()
@Column(name="twitteruserid")
private long twitterUserId = 0;

@Id
@Basic()
@Column(name="fetchtime")
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime fetchTime = null;

FYI, when used together with Spring Data JPA, it's required to remove the @Id and @Type annotations from the MappedSuperclass. If these are not removed, there will be errors bellow. It doesn't change the nature of this Hibernate bug, BTW.

org.springframework.data.mapping.model.MappingException: Ambiguous mapping! Annotation Id configured on field twitterUserId and one of its accessor methods in class TwitterFollowerCount!
    at org.springframework.data.mapping.model.AnnotationBasedPersistentProperty.populateAnnotationCache(AnnotationBasedPersistentProperty.java:111)
    at org.springframework.data.mapping.model.AnnotationBasedPersistentProperty.<init>(AnnotationBasedPersistentProperty.java:66)
    at org.springframework.data.jpa.mapping.JpaPersistentPropertyImpl.<init>(JpaPersistentPropertyImpl.java:86)
    at org.springframework.data.jpa.mapping.JpaMetamodelMappingContext.createPersistentProperty(JpaMetamodelMappingContext.java:67)
    at org.springframework.data.jpa.mapping.JpaMetamodelMappingContext.createPersistentProperty(JpaMetamodelMappingContext.java:35)
    at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.createAndRegisterProperty(AbstractMappingContext.java:449)
    at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.doWith(AbstractMappingContext.java:427)
    at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:607)
    at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:295)
    at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:257)
    at org.springframework.data.mapping.context.AbstractMappingContext.initialize(AbstractMappingContext.java:373)
    at org.springframework.data.jpa.repository.config.JpaRepositoryConfigExtension$JpaMetamodelMappingContextFactoryBean.createInstance(JpaRepositoryConfigExtension.java:216)
    at org.springframework.data.jpa.repository.config.JpaRepositoryConfigExtension$JpaMetamodelMappingContextFactoryBean.createInstance(JpaRepositoryConfigExtension.java:169)
    at org.springframework.beans.factory.config.AbstractFactoryBean.afterPropertiesSet(AbstractFactoryBean.java:134)
    at org.springframework.data.jpa.repository.config.JpaRepositoryConfigExtension$JpaMetamodelMappingContextFactoryBean.afterPropertiesSet(JpaRepositoryConfigExtension.java:230)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1612)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1549)
    ... 40 more
like image 138
Hendy Irawan Avatar answered Sep 25 '22 13:09

Hendy Irawan