【问题标题】:Hibernate / JPA: QueryException when hibernate generates metamodel for @ElementCollectionHibernate / JPA:当hibernate为@ElementCollection生成元模型时出现QueryException
【发布时间】:2014-02-22 10:29:32
【问题描述】:

我尝试在具有休眠 4.3.1.Final 的实体中保留 @ElementCollection。实体如下所示:

import javax.persistence.*;
import java.util.Map;
@Entity
public class MyEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    @ElementCollection
    private Map<CompositeKey, CompositeValue> map;

    @Embeddable
    public static class CompositeKey {
        @Basic
        private Integer key1;
        @Basic
        private Integer key2;
    }

    @Embeddable
    public static class CompositeValue {
        @Basic
        private Integer val1;
        @Basic
        private Integer val2;
    }
}

Hibernate 正确生成架构:

create table MyEntity (id integer not null, primary key (id)) ENGINE=InnoDB;
create table MyEntity_map (MyEntity_id integer not null, val1 integer, val2 integer, key1 integer, key2 integer, primary key (MyEntity_id, key1, key2)) ENGINE=InnoDB;
create table ReferencedEntity (id integer not null, primary key (id)) ENGINE=InnoDB;
alter table MyEntity_map add constraint FK_mhu8q8dtieguddm0w4gxfwhnc foreign key (MyEntity_id) references MyEntity (id);

但是当我将CompositeKey 更改为引用另一个Entity 时,当hibernate 在启动时生成元模型时,我得到一个QueryException

修改后的代码:

@Embeddable
public static class CompositeKey {
    @ManyToOne
    private ReferencedEntity key1;
    @Basic
    private Integer key2;
}

引用的Entity

import javax.persistence.*;
@Entity
public class ReferencedEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
}

例外:

Caused by: org.hibernate.QueryException: could not resolve property: key1 of: component[val1,val2]
    at org.hibernate.persister.entity.AbstractPropertyMapping.propertyException(AbstractPropertyMapping.java:83) ~[AbstractPropertyMapping.class:4.3.1.Final]
    at org.hibernate.persister.entity.AbstractPropertyMapping.toColumns(AbstractPropertyMapping.java:98) ~[AbstractPropertyMapping.class:4.3.1.Final]
    at org.hibernate.persister.collection.AbstractCollectionPersister.toColumns(AbstractCollectionPersister.java:1625) ~[AbstractCollectionPersister.class:4.3.1.Final]
    at org.hibernate.loader.plan.build.internal.spaces.CompositePropertyMapping.toColumns(CompositePropertyMapping.java:124) ~[CompositePropertyMapping.class:4.3.1.Final]
    at org.hibernate.loader.plan.build.internal.spaces.CompositeQuerySpaceImpl.toAliasedColumns(CompositeQuerySpaceImpl.java:52) ~[CompositeQuerySpaceImpl.class:4.3.1.Final]
    at org.hibernate.loader.plan.build.internal.spaces.JoinImpl.resolveAliasedLeftHandSideJoinConditionColumns(JoinImpl.java:79) ~[JoinImpl.class:4.3.1.Final]
    at org.hibernate.loader.plan.exec.internal.LoadQueryJoinAndFetchProcessor.addJoins(LoadQueryJoinAndFetchProcessor.java:261) ~[LoadQueryJoinAndFetchProcessor.class:4.3.1.Final]
    at org.hibernate.loader.plan.exec.internal.LoadQueryJoinAndFetchProcessor.renderEntityJoin(LoadQueryJoinAndFetchProcessor.java:193) ~[LoadQueryJoinAndFetchProcessor.class:4.3.1.Final]
    at org.hibernate.loader.plan.exec.internal.LoadQueryJoinAndFetchProcessor.renderJoin(LoadQueryJoinAndFetchProcessor.java:158) ~[LoadQueryJoinAndFetchProcessor.class:4.3.1.Final]
    at org.hibernate.loader.plan.exec.internal.LoadQueryJoinAndFetchProcessor.processQuerySpaceJoin(LoadQueryJoinAndFetchProcessor.java:137) ~[LoadQueryJoinAndFetchProcessor.class:4.3.1.Final]
    at org.hibernate.loader.plan.exec.internal.LoadQueryJoinAndFetchProcessor.processQuerySpaceJoins(LoadQueryJoinAndFetchProcessor.java:132) ~[LoadQueryJoinAndFetchProcessor.class:4.3.1.Final]
    at org.hibernate.loader.plan.exec.internal.LoadQueryJoinAndFetchProcessor.processQuerySpaceJoin(LoadQueryJoinAndFetchProcessor.java:138) ~[LoadQueryJoinAndFetchProcessor.class:4.3.1.Final]
    at org.hibernate.loader.plan.exec.internal.LoadQueryJoinAndFetchProcessor.processQuerySpaceJoins(LoadQueryJoinAndFetchProcessor.java:132) ~[LoadQueryJoinAndFetchProcessor.class:4.3.1.Final]
    at org.hibernate.loader.plan.exec.internal.LoadQueryJoinAndFetchProcessor.processQuerySpaceJoins(LoadQueryJoinAndFetchProcessor.java:113) ~[LoadQueryJoinAndFetchProcessor.class:4.3.1.Final]
    at org.hibernate.loader.plan.exec.internal.AbstractLoadQueryDetails.generate(AbstractLoadQueryDetails.java:171) ~[AbstractLoadQueryDetails.class:4.3.1.Final]
    at org.hibernate.loader.plan.exec.internal.BasicCollectionLoadQueryDetails.<init>(BasicCollectionLoadQueryDetails.java:60) ~[BasicCollectionLoadQueryDetails.class:4.3.1.Final]
    at org.hibernate.loader.plan.exec.internal.BatchingLoadQueryDetailsFactory.makeCollectionLoadQueryDetails(BatchingLoadQueryDetailsFactory.java:101) ~[BatchingLoadQueryDetailsFactory.class:4.3.1.Final]
    at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.<init>(AbstractLoadPlanBasedCollectionInitializer.java:77) ~[AbstractLoadPlanBasedCollectionInitializer.class:4.3.1.Final]
    at org.hibernate.loader.collection.plan.CollectionLoader.<init>(CollectionLoader.java:112) ~[CollectionLoader.class:4.3.1.Final]
    at org.hibernate.loader.collection.plan.CollectionLoader$Builder.byKey(CollectionLoader.java:105) ~[CollectionLoader$Builder.class:4.3.1.Final]
    at org.hibernate.loader.collection.plan.AbstractBatchingCollectionInitializerBuilder.buildNonBatchingLoader(AbstractBatchingCollectionInitializerBuilder.java:45) ~[AbstractBatchingCollectionInitializerBuilder.class:4.3.1.Final]
    at org.hibernate.loader.collection.BatchingCollectionInitializerBuilder.createBatchingCollectionInitializer(BatchingCollectionInitializerBuilder.java:71) ~[BatchingCollectionInitializerBuilder.class:4.3.1.Final]
    at org.hibernate.persister.collection.BasicCollectionPersister.createCollectionInitializer(BasicCollectionPersister.java:343) ~[BasicCollectionPersister.class:4.3.1.Final]
    at org.hibernate.persister.collection.AbstractCollectionPersister.postInstantiate(AbstractCollectionPersister.java:676) ~[AbstractCollectionPersister.class:4.3.1.Final]
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:484) ~[SessionFactoryImpl.class:4.3.1.Final]
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1857) ~[Configuration.class:4.3.1.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850) ~[EntityManagerFactoryBuilderImpl$4.class:4.3.1.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:843) ~[EntityManagerFactoryBuilderImpl$4.class:4.3.1.Final]
    at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:399) ~[ClassLoaderServiceImpl.class:4.3.1.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:842) ~[EntityManagerFactoryBuilderImpl.class:4.3.1.Final]
    at org.hibernate.jpa.HibernatePersistenceProvider.createContainerEntityManagerFactory(HibernatePersistenceProvider.java:150) ~[HibernatePersistenceProvider.class:4.3.1.Final]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:336) ~[LocalContainerEntityManagerFactoryBean.class:4.0.1.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318) ~[AbstractEntityManagerFactoryBean.class:4.0.1.RELEASE]
    ...

我的映射有什么问题?如何防止此异常?

有趣的是,BasicCollectionPersister 似乎已正确初始化。调试显示,例如sqlUpdateRowStringupdate MyEntity_map set val1=?, val2=? where MyEntity_id=? and key1_id=? and key2=?

【问题讨论】:

  • 您使用的是哪个 Hibernate 版本?
  • 我使用的是休眠 4.3.1.Final。

标签: java hibernate jpa hibernate-mapping


【解决方案1】:

来自 JPA 2.0 规范:

不支持在嵌入式 id 类中定义的关系映射。

另见JPA - EmbeddedId with @ManytoOne

编辑:

Hibernate 4.3.1.Final 实现了 JPA 2.1,所以我的第一个猜测是错误的。过失。

映射的问题是使用@ElementCollection 和一个可嵌入的CompositeKey 引用实体ReferencedEntity。当 Hibernate 查找从 CompositeValue(原文如此!)到 ReferencedEntity 的引用时,会引发 AbstractPropertyMapping 中的异常。但是,由于不存在这种关系,因此会引发异常。对我来说,不清楚这是 Hibernate 错误还是根据 JPA 2.1 规范。

我看到以下解决方案。

解决方案 1

CompositeKey 更改为Entity 添加id 字段。在这种情况下,可以使用 @OneToMany 注释:

@Entity
public class CompositeKey {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @ManyToOne(targetEntity = ReferencedEntity.class)
    private ReferencedEntity key1;

    @Basic
    private Integer key2;

}

解决方案 2

添加一个附加实体CompositeSampler,其中包含CompositeKey 作为ID,CompositeValue 作为附加属性。 MyEntity 将包含CompositeSampler 的列表。

解决方案 3

添加从CompositeValueReferencedEntity 的引用。

顺便说一下,根据 JPA 2.1 规范:“如果将可嵌入类用作映射键,则可嵌入类必须实现与可嵌入类映射到的数据库列一致的 hashCode 和 equals 方法”。

【讨论】:

  • 除了将CompositeKey 声明为@Entity 之外,是否有其他解决方法?
  • 我不确定这是否真的是问题所在,因为休眠将@EmbeddedIds 与@ManyToOne 元素按预期映射并正确生成外键。而且我什至没有在上面发布的代码中使用@EmbeddedId
  • 感谢您的更新。解决方案 1 是我对您的回答的第一条评论的意思。我认为这是休眠中的一个错误,因为当我将字段key1 重命名为val1 时,我能够让休眠生成模式。它在CompositeValue 中找到属性名称,并且不再抱怨。但我没有测试实体 的行为 是否符合预期 (CRUD)。我想我会提交一份错误报告。
猜你喜欢
  • 1970-01-01
  • 2016-11-10
  • 2017-11-27
  • 2021-12-22
  • 2020-03-06
  • 1970-01-01
  • 1970-01-01
  • 2019-09-22
  • 2015-06-30
相关资源
最近更新 更多