I'm attempting to sort out some bumps in the road I've encountered with this entity mode. I'd like to use it as typically described, as a transport between databases using replicate.
Please note these mappings are dynamic map entity mode.
The only way this stuff works is if I have embed-xml=false on the Collection in the Root entity and embed-xml=true on the inverse many-to-one in Typical entity. However, I would like to have NO embed-xml since I may only transport certain subsets of data. If I change the Typical embed-xml to false, I get the following:
Code:
java.lang.String cannot be cast to org.dom4j.Element
java.lang.ClassCastException: java.lang.String cannot be cast to org.dom4j.Element
at org.hibernate.property.Dom4jAccessor$AttributeGetter.get(Dom4jAccessor.java:194)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.getVersion(AbstractEntityTuplizer.java:264)
at org.hibernate.persister.entity.AbstractEntityPersister.getVersion(AbstractEntityPersister.java:3629)
at org.hibernate.persister.entity.AbstractEntityPersister.isTransient(AbstractEntityPersister.java:3347)
at org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:204)
at org.hibernate.engine.ForeignKeys$Nullifier.isNullifiable(ForeignKeys.java:160)
at org.hibernate.engine.ForeignKeys$Nullifier.nullifyTransientReferences(ForeignKeys.java:92)
at org.hibernate.engine.ForeignKeys$Nullifier.nullifyTransientReferences(ForeignKeys.java:70)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:311)
at org.hibernate.event.def.DefaultReplicateEventListener.onReplicate(DefaultReplicateEventListener.java:145)
at org.hibernate.impl.SessionImpl.fireReplicate(SessionImpl.java:959)
at org.hibernate.impl.SessionImpl.replicate(SessionImpl.java:946)
at com.ciminc.compass.synchronizer.Dom4jSerializationTest.dom4jReplicateSimpleGraph(Dom4jSerializationTest.java:182)
The XML output as a result of the BAD embed-xml=false on Typical with all embed-xml=false on Root:
Code:
<Root guid="4028B881286F240C01286F24248C0009" version="0">
<uniqueOne>one</uniqueOne>
<uniqueTwo>two</uniqueTwo>
</Root>
<Typical guid="4028B881286F240C01286F24248E000A" version="0">
<root>4028B881286F240C01286F24248C0009</root>
<uniqueOne>one</uniqueOne>
</Typical>
The working code with embed-xml=true:
Mappings
Code:
<hibernate-mapping>
<class entity-name="Root" table="ROOT" node="Root">
<id name="guid" type="com.ciminc.hibernate.type.GuidType" node="@guid">
<column name="GUID"/>
<generator class="org.hibernate.id.UUIDHexGenerator"/>
</id>
<natural-id mutable="true">
<property name="uniqueOne" type="string" unique="true">
<column name="UNIQUE_ONE"/>
</property>
<property name="uniqueTwo" type="string" unique="true">
<column name="UNIQUE_TWO"/>
</property>
</natural-id>
<version name="version" type="java.lang.Long" node="@version">
<column name="VERSION"/>
</version>
<bag name="typicals" inverse="true" table="TYPICAL" fetch="select" cascade="save-update,replicate,evict" embed-xml="false">
<key on-delete="noaction">
<column name="ROOT_GUID" not-null="true"/>
</key>
<one-to-many entity-name="Typical" embed-xml="false" node="Typical"/>
</bag>
</class>
<class entity-name="Typical" table="TYPICAL" node="Typical">
<id name="guid" type="com.ciminc.hibernate.type.GuidType" node="@guid">
<column name="GUID"/>
<generator class="org.hibernate.id.UUIDHexGenerator"/>
</id>
<natural-id mutable="true">
<many-to-one name="root" entity-name="Root" unique="true" embed-xml="true" node="root">
<column name="ROOT_GUID" not-null="true"/>
</many-to-one>
<property name="uniqueOne" type="string" unique="true">
<column name="UNIQUE_ONE"/>
</property>
</natural-id>
<version name="version" type="java.lang.Long" node="@version">
<column name="VERSION"/>
</version>
<property name="displaystring" type="string">
<column name="DISPLAYSTRING"/>
</property>
</class>
</hibernate-mapping>
Test
Code:
@Test
public void dom4jReplicateSimpleGraph() throws IOException, DocumentException {
log.info("Beginning dom4j");
List<Element> elements = null;
Map<String,Object> rootObj = null;
Map<String,Object> typicalObj = null;
Session dom4jSession = sessionLocal.getSession(EntityMode.DOM4J);
assertEquals(0, dom4jSession.createQuery("from Root").list().size());
// Create a local graph
rootObj = new HashMap<String,Object>();
rootObj.put("uniqueOne", "one");
rootObj.put("uniqueTwo", "two");
rootObj.put("typicals", new ArrayList());
typicalObj = new HashMap<String,Object>();
typicalObj.put("uniqueOne", "one");
typicalObj.put("root", rootObj);
((List)rootObj.get("typicals")).add(typicalObj);
sessionLocal.save("Root", rootObj);
sessionLocal.flush();
assertEquals(1, sessionLocal.createQuery("from Root").list().size());
assertEquals(1, sessionLocal.createQuery("from Typical").list().size());
sessionLocal.clear();
Document dom4jDoc = new DefaultDocument();
Element syncElement = new DefaultElement("synchronization-set");
dom4jDoc.add(syncElement);
// Add Roots...no embedded-xml
elements = dom4jSession.createQuery("from Root").list();
assertEquals(1, elements.size());
for (Element rootElement: elements) {
syncElement.add(rootElement);
}
dom4jSession.clear();
// Add Typicals since Root references
elements = dom4jSession.createQuery("from Typical").list();
assertEquals(1, elements.size());
for (Element rootElement: elements) {
syncElement.add(rootElement);
}
dom4jSession.clear();
XMLWriter writer = new XMLWriter(new FileWriter("target/serialize-entities.xml"));//, OutputFormat.createPrettyPrint());
writer.write(dom4jDoc);
writer.close();
sessionLocal.getTransaction().rollback();
sessionLocal.beginTransaction();
assertEquals(0, sessionLocal.createQuery("from Root").list().size());
sessionLocal.clear();
SAXReader reader = new SAXReader();
dom4jDoc = reader.read("target/serialize-entities.xml");
//syncElement = dom4jDoc.getRootElement();
for (Object elObj: dom4jDoc.getRootElement().elements()) {
if (elObj instanceof DefaultElement) {
Element rootElement = (Element) elObj;
dom4jSession.replicate(rootElement, ReplicationMode.OVERWRITE);
}
}
dom4jSession.flush();
assertEquals(1, sessionLocal.createQuery("from Root").list().size());
assertEquals(1, sessionLocal.createQuery("from Typical").list().size());
}
I edit the mappings a little on pasting because they were a bit more verbose, if there's issues, let me know and I'll fix them.