Hibernate version:
3.1.2
Short description:
I'm using merge (for reasons I won't get into now) to persist an object graph containing multiple new entities. Hibernate throws an exception when one new entity references another new entity via <any ...>
Long description:
I have an <any ...> mapping on an entity that can be "owned" by other types of entities:
Code:
<class name="com...PermissionsImpl"
table="policy_permissions" ...>
...
<any name="owner" id-type="java.lang.Long" meta-type="string">
<meta-value value="PolicyKey" class="com...PolicyKeyImpl"/>
<meta-value value="PolicyScope" class="com...PolicyScopeImpl"/>
<column name="owner_type"/>
<column name="owner_id"/>
</any>
...
The PolicyKey entity maintains a map of these permissions:
Code:
<map name="scopeToPermissions"
table="policy_scope_permissions"
cascade="persist,merge,save-update"
lazy="false">
<key column="policy_id"/>
<map-key-many-to-many column="scope_id" class="com...PolicyScopeImpl"/>
<many-to-many column="permissions_id" class="com...PermissionsImpl"/>
</map>
I have code that creates new Permissions and sets them up on a new PolicyKey. This code eventually calls session.merge(...) with these new instances by passing in the new PolicyKey:
Code:
session.merge(newPolicy);
The call to merge leads to an exception:
Code:
org.hibernate.TransientObjectException: com...PolicyKeyImpl
at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:216)
at org.hibernate.type.AnyType.replace(AnyType.java:223)
at org.hibernate.type.AbstractType.replace(AbstractType.java:153)
at org.hibernate.type.TypeFactory.replace(TypeFactory.java:447)
at org.hibernate.event.def.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:302)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:159)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:103)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:711)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:693)
at org.hibernate.engine.CascadingAction$6.cascade(CascadingAction.java:156)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:213)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:157)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:108)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:290)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:185)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:160)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:108)
at org.hibernate.engine.Cascade.cascade(Cascade.java:248)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:410)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:174)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:103)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:52)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:701)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:685)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:689)
...
I should note that we use assigned IDs, and so use a null version property to indicate a new instance. Mapped like this:
Code:
<id name="id" column="id" type="java.lang.Long" unsaved-value="undefined">
<generator class="assigned"/>
</id>
<version name="version" type="long" column="version" access="property" unsaved-value="null"/>
Am I doing something wrong, or is this expected behavior?
Thanks,
Anodos