Composite Key in JPA / Hibernate with inherited cl

2019-03-14 01:30发布

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

3条回答
We Are One
2楼-- · 2019-03-14 02:10

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
查看更多
forever°为你锁心
3楼-- · 2019-03-14 02:12

Actually bumped into the same problem.

As:

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

Does seem to work, I would deem it a bug. See https://hibernate.atlassian.net/browse/HHH-9114.

查看更多
▲ chillily
4楼-- · 2019-03-14 02:17

From the JPA spec:

The primary key must be defined on the entity class that is the root of the entity hierarchy or on a mapped superclass that is a (direct or indirect) superclass of all entity classes in the entity hierarchy. The primary key must be defined exactly once in an entity hierarchy.

So according to JPA you can't redefine the @Id. I wouldn't call this a bug.

Although the workaround given as answer here might work, it may happen that for other JPA frameworks it doesn't work.

查看更多
登录 后发表回答