@MapKey引用以可嵌入映射值映射的列时的AnnotationException

时间:2018-04-20 11:13:20

标签: hibernate hibernate-mapping

用例

我有一个User实体,其中包含UserProfiles的地图,您可以看到UserProfile被映射为Element集合,而不是单个实体。

@Entity
@Table(name = "user_")
public class User extends AbstractEntity<UserId> {

    ...

    @ElementCollection
    @CollectionTable(name = "user_profile")
    @MapKey(name = "userProfileType")
    @MapKeyEnumerated(STRING)
    private Map<UserProfileType, UserProfile> userProfiles;

}

@Embeddable
@NoArgsConstructor(access = PACKAGE)
@AllArgsConstructor(staticName = "of")
@EqualsAndHashCode
public class UserProfile {

    @Enumerated(STRING)
    private UserProfileType userProfileType;

    ...

}

注意:我正在使用Hibernate 5.2.14。

问题

当Hibernate处理这些映射时,我可以出现以下异常:

Caused by: org.hibernate.AnnotationException: Associated class not found: UserProfile
    at org.hibernate.cfg.annotations.MapBinder.bindKeyFromAssociationTable(MapBinder.java:168) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.cfg.annotations.MapBinder.access$000(MapBinder.java:66) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.cfg.annotations.MapBinder$1.secondPass(MapBinder.java:101) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:54) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1635) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1603) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:278) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:861) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:888) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:57) ~[spring-orm-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) ~[spring-orm-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:388) ~[spring-orm-5.0.4.RELEASE.jar:5.0.4.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:377) ~[spring-orm-5.0.4.RELEASE.jar:5.0.4.RELEASE]

尝试了解决方法

我尝试使用@MapKeyColumn代替@MapKey,但这会产生另一个错误,声称列user_profile_type的物理表示已经存在。

问题

我想知道这是否应该按照JPA规范运作?

我认为它应该可行,因为我发现了一个已经在Hibernate 5中修复过的非常类似的问题:https://hibernate.atlassian.net/browse/HHH-5393

感谢您的帮助!

干杯, 拉斯洛

1 个答案:

答案 0 :(得分:0)

尽管最近我还没有从事这个项目,但是我可以看到在将问题发布到SoF几天后,我以以下方式将代码检查到了Git中。

@Entity
@Table(name = "user_")
public class User extends AbstractEntity<UserId> {

  ...

  @ElementCollection
  @CollectionTable(name = "user_profile")
  @MapKeyColumn(name = "user_profile_type", insertable = false, updatable = false)
  @MapKeyEnumerated(STRING)
  private Map<UserProfileType, UserProfile> userProfiles;

  ...

}

@Embeddable
@NoArgsConstructor(access = PACKAGE)
@AllArgsConstructor(staticName = "of")
@EqualsAndHashCode
@ToString(of = {"userProfileType", "fullName"})
public class UserProfile {

  @Enumerated(STRING)
  @Column(name = "user_profile_type")
  private UserProfileType userProfileType;

  ...

}

public enum UserProfileType {
  FACEBOOK, GOOGLE;
}

我认为,技巧一定是在添加insertable = false, updatable = false,这样可以消除已经定义了user_profile_type的错误。