I am having trouble saving an entity that contains a component which, in turn, contains a collection that is mapped one-to-many with a non-null foreign key. Loading instances (with session.get) of the entity works fine.
If I map the key with not-null="false", saving works. Also if the the collection is directly contained in the entity (i.e., not in a component) saving works.
The manifestation of the problem is a MappingException (full trace below). The problem seems to be that getOwnerId in PersistenceContext assumes that collections are directly contained within entities. Is this required? (The manual doesn't specify whether components may contain collections.)
The code samples & other info below are from a self-contained, simplified test case which I'd be happy to provide.
Any suggestions appreciated.
Hibernate version: 3.0.4
Mapping documents:
Code:
<hibernate-mapping package="eg.domain">
<class name="Spoke" table="t_spoke">
<id name="id"><generator class="identity"/></id>
<property name="angle" insert="false" update="false"/>
</class>
<class name="Axle" table="t_axle">
<id name="id"><generator class="identity"/></id>
<component name="spokes">
<map name="byAngle" cascade="all,delete-orphan">
<key column="axle_id" not-null="true"/>
<map-key type="integer" column="angle"/>
<one-to-many class="Spoke"/>
</map>
</component>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
Axle aNew = new Axle();
aNew.setSpokes(new Spokes());
for (int i = 0 ; i < 4 ; i++) {
Spoke s = new Spoke(i * 90);
aNew.getSpokes().getByAngle().put(s.getAngle(), s);
}
System.out.println("Trying to save aNew = " + aNew);
session.saveOrUpdate(aNew);
Full stack trace of any exception that occurs:Code:
Exception in thread "main" org.hibernate.MappingException: Unknown entity: eg.domain.Axle.eg.domain.Axle.spokes
at org.hibernate.impl.SessionFactoryImpl.getEntityPersister(SessionFactoryImpl.java:569)
at org.hibernate.engine.PersistenceContext.getOwnerId(PersistenceContext.java:1023)
at org.hibernate.property.BackrefPropertyAccessor$BackrefGetter.getForInsert(BackrefPropertyAccessor.java:80)
at org.hibernate.tuple.AbstractTuplizer.getPropertyValuesToInsert(AbstractTuplizer.java:189)
at org.hibernate.tuple.PojoTuplizer.getPropertyValuesToInsert(PojoTuplizer.java:194)
at org.hibernate.persister.entity.BasicEntityPersister.getPropertyValuesToInsert(BasicEntityPersister.java:3005)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:215)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:159)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:104)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:184)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:173)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:96)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:69)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:468)
at org.hibernate.engine.Cascades$5.cascade(Cascades.java:154)
at org.hibernate.engine.Cascades.cascadeAssociation(Cascades.java:771)
at org.hibernate.engine.Cascades.cascade(Cascades.java:720)
at org.hibernate.engine.Cascades.cascadeCollection(Cascades.java:895)
at org.hibernate.engine.Cascades.cascadeAssociation(Cascades.java:792)
at org.hibernate.engine.Cascades.cascade(Cascades.java:720)
at org.hibernate.engine.Cascades.cascade(Cascades.java:739)
at org.hibernate.engine.Cascades.cascade(Cascades.java:847)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:362)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:264)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:159)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:104)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:184)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:173)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:96)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:69)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:468)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:463)
at eg.Main.main(Main.java:32)
Name and version of the database you are using: HSQLDB 1.7.2
Debug level Hibernate log excerpt:
DEBUG org.hibernate.event.def.AbstractSaveEventListener : transient instance of: eg.domain.Axle
DEBUG org.hibernate.event.def.DefaultSaveOrUpdateEventListener : saving transient instance
DEBUG org.hibernate.event.def.AbstractSaveEventListener : generated identifier: , using strategy: org.hibernate.id.IdentityGenerator
DEBUG org.hibernate.event.def.AbstractSaveEventListener : saving [eg.domain.Axle#<null>]
DEBUG org.hibernate.event.def.AbstractSaveEventListener : executing insertions
DEBUG org.hibernate.engine.Cascades : processing cascade ACTION_SAVE_UPDATE for: eg.domain.Axle
DEBUG org.hibernate.engine.Cascades : done processing cascade ACTION_SAVE_UPDATE for: eg.domain.Axle
DEBUG org.hibernate.event.def.WrapVisitor : Wrapped collection in role: eg.domain.Axle.eg.domain.Axle.spokes.byAngle
DEBUG org.hibernate.persister.entity.BasicEntityPersister : Inserting entity: eg.domain.Axle (native id)
DEBUG org.hibernate.jdbc.AbstractBatcher : about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG org.hibernate.SQL : insert into t_axle (id) values (null)
DEBUG org.hibernate.jdbc.AbstractBatcher : preparing statement
DEBUG org.hibernate.persister.entity.BasicEntityPersister : Dehydrating entity: [eg.domain.Axle#<null>]
DEBUG org.hibernate.jdbc.AbstractBatcher : about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG org.hibernate.jdbc.AbstractBatcher : closing statement
DEBUG org.hibernate.SQL : call identity()
DEBUG org.hibernate.jdbc.AbstractBatcher : about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG org.hibernate.SQL : call identity()
DEBUG org.hibernate.jdbc.AbstractBatcher : preparing statement
DEBUG org.hibernate.id.IdentifierGeneratorFactory : Natively generated identity: 9
DEBUG org.hibernate.jdbc.AbstractBatcher : about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG org.hibernate.jdbc.AbstractBatcher : closing statement
DEBUG org.hibernate.engine.Cascades : processing cascade ACTION_SAVE_UPDATE for: eg.domain.Axle
DEBUG org.hibernate.engine.Cascades : cascade ACTION_SAVE_UPDATE for collection: eg.domain.Axle.eg.domain.Axle.spokes.byAngle
DEBUG org.hibernate.engine.Cascades : cascading to saveOrUpdate: eg.domain.Spoke
DEBUG org.hibernate.event.def.AbstractSaveEventListener : transient instance of: eg.domain.Spoke
DEBUG org.hibernate.event.def.DefaultSaveOrUpdateEventListener : saving transient instance
DEBUG org.hibernate.event.def.AbstractSaveEventListener : generated identifier: , using strategy: org.hibernate.id.IdentityGenerator
DEBUG org.hibernate.event.def.AbstractSaveEventListener : saving [eg.domain.Spoke#<null>]
DEBUG org.hibernate.event.def.AbstractSaveEventListener : executing insertions