Note. I designed this SSSCE to illustrate my problem. The actual problem is much larger (individual "records" have much more fields and much more data, and the XML data file has 30 thousand records.)
Given the following XML fragment:
<?xml version="1.0" encoding="UTF-8"?>
<manufacturers>
<manufacturer>
<name>BMW</name>
<manufacturing-countries>
<country code="DE" iso="DEU">Germany</country>
</manufacturing-countries>
<using-countries>
<country code="DE" iso="DEU">Germany</country>
<country code="JP" iso="JPN">Japan</country>
<country code="US" iso="USA">United States</country>
<country code="UK" iso="GBR">Germany</country>
</using-countries>
</manufacturer>
<manufacturer>
<name>Honda</name>
<manufacturing-countries>
<country code="JP" iso="JPN">Japan</country>
<country code="US" iso="USA">United States</country>
</manufacturing-countries>
<using-countries>
<country code="JP" iso="JPN">Japan</country>
<country code="US" iso="USA">United States</country>
<country code="UK" iso="GBR">Germany</country>
</using-countries>
</manufacturer>
</manufacturers>
I have a JAX-B parser that reads this XML into the following objects (note that the objects are intended for immutability, they use the builder pattern to create real objects):
public class Country {
private String code;
private String name;
private String isoCode;
private Country() {
}
}
public class Manufacturer {
private String name;
private List<Country> manufacturingCountries;
private List<Country> usingCountries;
private Manufacturer() {
}
}
So, in my code, I can easily load the list of manufacturers from an XML file:
List<Manufacturer> manufacturers = ManufacturerReader.readManufacturersFromXml(xmlFilePath);
I need to turn around and put this information in a database. So far I have a Hibernate mapping file:
hibernate.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-access="field">
<class name="Country"
table="COUNTRIES">
<id
name="code"
length="2"
column="CODE">
<generator class="assigned"/>
</id>
<property
name="name"
length="40"
column="NAME">
</property>
<property
name="isoCode"
length="3"
column="ISO_CODE">
</property>
</class>
<class name="Manufacturer"
table="MANUFACTURERS">
<id
type="string"
column="ID">
<generator class="uuid"/>
</id>
<property
name="name"
length="255"
column="NAME">
</property>
<list
name="manufacturingCountries"
table="MANUF_MANUF_COUNTRY"
cascade="save-update">
<key column="MANUFACTURER_ID"/>
<list-index column="POSITION"/>
<many-to-many class="Country" column="COUNTRY_CODE"/>
</list>
<list
name="usingCountries"
table="MANUF_USING_COUNTRY"
cascade="save-update">
<key column="MANUFACTURER_ID"/>
<list-index column="POSITION"/>
<many-to-many class="Country" column="COUNTRY_CODE"/>
</list>
</class>
</hibernate-mapping>
, , (, "" , "JP" ..),
Hibernate, NonUniqueObjectException - () .
Exception in thread "main" org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [Country
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:190)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:143)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:117)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:685)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:677)
at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:252)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:425)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:362)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:338)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
at org.hibernate.engine.Cascade.cascade(Cascade.java:161)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:475)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:353)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:143)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:713)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:701)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:697)
at Main.main(Main.java:28)
"" XML-, ?
:
- " ",
hibernate mapping file (s).
- ( API .)
- XML-/ ( , API).
- XML- ( , API
.)
1:
, :
import java.util.List;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class Main {
public static void main(String[] args) {
List<Manufacturer> manuf = ManufacturerXmlReader.readManufacturersFromXml("manufacturers.xml");
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
for (Manufacturer m : manuf) {
session.save(m);
}
tx.commit();
session.close();
HibernateUtil.shutdown();
}
}
2:
session.save() session.merge()
Exception in thread "main" org.hibernate.HibernateException: The class has no identifier property: Manufacturer
at org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:220)
at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:3876)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:233)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:84)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:867)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:851)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:855)
at Main.main(Main.java:16)
3:
Hibernate, name, :
<class name="Manufacturer"
table="MANUFACTURERS">
<id
name="id"
type="string"
column="ID">
<generator class="uuid"/>
</id>
:
Initial SessionFactory creation failed.org.hibernate.PropertyNotFoundException: field [id] not found on Manufacturer
Exception in thread "main" java.lang.ExceptionInInitializerError
at HibernateUtil.<clinit>(HibernateUtil.java:21)
at Main.main(Main.java:11)
Caused by: org.hibernate.PropertyNotFoundException: field [id] not found on Manufacturer
at org.hibernate.property.DirectPropertyAccessor.getField(DirectPropertyAccessor.java:182)
at org.hibernate.property.DirectPropertyAccessor.getField(DirectPropertyAccessor.java:174)
at org.hibernate.property.DirectPropertyAccessor.getGetter(DirectPropertyAccessor.java:197)
at org.hibernate.tuple.PropertyFactory.getGetter(PropertyFactory.java:191)
at org.hibernate.tuple.PropertyFactory.buildIdentifierProperty(PropertyFactory.java:67)
at org.hibernate.tuple.entity.EntityMetamodel.<init>(EntityMetamodel.java:135)
at org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEntityPersister.java:485)
at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:133)
at org.hibernate.persister.PersisterFactory.createClassPersister(PersisterFactory.java:84)
at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:286)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1872)
at HibernateUtil.<clinit>(HibernateUtil.java:17)
... 1 more
name/field ID,
<id
name="name"
length="255"
column="NAME">
<generator class="assigned"/>
</id>
:
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [Country
at org.hibernate.impl.SessionFactoryImpl$2.handleEntityNotFound(SessionFactoryImpl.java:435)
at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:233)
at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:285)
at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:152)
at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:1090)
at org.hibernate.impl.SessionImpl.internalLoad(SessionImpl.java:1038)
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:630)
at org.hibernate.type.EntityType.resolve(EntityType.java:438)
at org.hibernate.type.EntityType.replace(EntityType.java:298)
at org.hibernate.type.CollectionType.replaceElements(CollectionType.java:508)
at org.hibernate.type.CollectionType.replace(CollectionType.java:575)
at org.hibernate.type.AbstractType.replace(AbstractType.java:176)
at org.hibernate.type.TypeHelper.replaceAssociations(TypeHelper.java:262)
at org.hibernate.event.def.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:589)
at org.hibernate.event.def.DefaultMergeEventListener.mergeTransientEntity(DefaultMergeEventListener.java:389)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:303)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:464)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:255)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:84)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:867)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:851)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:855)
at Main.main(Main.java:16)
Exception in thread "main" org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [Country
at org.hibernate.impl.SessionFactoryImpl$2.handleEntityNotFound(SessionFactoryImpl.java:435)
at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:233)
at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:285)
at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:152)
at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:1090)
at org.hibernate.impl.SessionImpl.internalLoad(SessionImpl.java:1038)
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:630)
at org.hibernate.type.EntityType.resolve(EntityType.java:438)
at org.hibernate.type.EntityType.replace(EntityType.java:298)
at org.hibernate.type.CollectionType.replaceElements(CollectionType.java:508)
at org.hibernate.type.CollectionType.replace(CollectionType.java:575)
at org.hibernate.type.AbstractType.replace(AbstractType.java:176)
at org.hibernate.type.TypeHelper.replaceAssociations(TypeHelper.java:262)
at org.hibernate.event.def.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:589)
at org.hibernate.event.def.DefaultMergeEventListener.mergeTransientEntity(DefaultMergeEventListener.java:389)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:303)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:464)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:255)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:84)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:867)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:851)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:855)
at Main.main(Main.java:16)