I try to persist an @ElementCollection
within an entity with hibernate 4.3.1.Final. The entity looks like this:
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 generates the schema correctly:
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);
But when I change CompositeKey
to reference another Entity
, I get a QueryException
when hibernate generates the metamodel on startup.
The changed code:
@Embeddable
public static class CompositeKey {
@ManyToOne
private ReferencedEntity key1;
@Basic
private Integer key2;
}
The referenced Entity
:
import javax.persistence.*;
@Entity
public class ReferencedEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
}
The Exception:
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]
...
What is wrong with my mapping? How can I prevent this exception?
It is interesting, that the BasicCollectionPersister
seems to get initialized correctly. Debugging shows, that eg the sqlUpdateRowString
is update MyEntity_map set val1=?, val2=? where MyEntity_id=? and key1_id=? and key2=?
update MyEntity_map set val1=?, val2=? where MyEntity_id=? and key1_id=? and key2=?
.
From the JPA 2.0 specification:
Relationship mappings defined within an embedded id class are not supported.
See also JPA - EmbeddedId with @ManytoOne .
EDIT:
Hibernate 4.3.1.Final implements JPA 2.1, so my first guess was wrong. Mea culpa.
The problem with the mapping is the use of @ElementCollection
with an embeddable CompositeKey
referencing to the entity ReferencedEntity
. The exception in AbstractPropertyMapping
is thrown when Hibernate looks for a reference from CompositeValue
(sic!) to ReferencedEntity
. However as no such relation exists, the exception is thrown. For me it is unclear if this is a Hibernate bug or according the JPA 2.1 specs.
I see following solutions.
Solution 1
Change CompositeKey
to an Entity
adding an id
field. In this case the @OneToMany
annotation could be used:
@Entity
public class CompositeKey {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@ManyToOne(targetEntity = ReferencedEntity.class)
private ReferencedEntity key1;
@Basic
private Integer key2;
}
Solution 2
Add an additional entity CompositeSampler
containing CompositeKey
as the ID and CompositeValue
as an additional attribute. MyEntity
will contain a list of CompositeSampler
.
Solution 3
Add a reference from CompositeValue
to ReferencedEntity
.
By the way, according the JPA 2.1 specs: "If an embeddable class is used as a map key, the embeddable class must implement the hashCode and equals methods consistently with the database columns to which the embeddable is mapped".
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.