I'm working on an Eclipse RCP application using Hibernate n MySQL for the primary data storage. I have a use case whereby a user will want to work remotely for a day. Sooo, the application creates a new HSQLDB on the user's local machine and I 'replicate' selected parts of the main DB onto their local DB. The use case allows me to create a clean/new/blank DB on the user's machine every time they want to work remotely so I don't have an issue with generated object IDs.....
The model is pretty basic, I have a single Location object, which contains a Set of Persons. There is more to the model but I can replicate this problem with just these two objects.
The Hibernate layer uses lazy object loading but I've been successful in bringing all relevent objects into memory before the replicate (using Hibernate.initialize(obj)).
The code then evicts the top level object (which evicts the remainder of the object graph).
I then open a new session factory pointing to the new DB, open a new session and try 'session.replicate(obj).'
What happens? Well, if I have a single Location (root) object and a single Person object, everything works fine. However, if I have more than one Person object in the set in the Location, only one Person object is persisted in the new DB.
However, when I tried setting the log4j logging properties to have 'org.hibernate=debug' dumped to my log file, the session.replicate() method replicated the entire graph into the new DB!!
I've tried this many times and I can 'replicate' the problem with ease (sorry about the pun).
I've isolated the Hibernate package that, when debugging is on, causes the session.replicate() to work. It is 'org.hibernate.type.'
Details follow.
Hibernate version:
3.2.2
Mapping documents:
Code:
<class name="Location" table="LOCATION">
<id name="key" column="locationKey">
<generator class="native"/>
</id>
<timestamp name="Ts" column="ts" source="vm"/>
<property name="Name" type="string" column="name" length="128"/>
<set name="Persons"
inverse="true"
cascade="all-delete-orphan">
<key column="locationKey"/>
<one-to-many class="Person"/>
</set>
</class>
<class name="Person" table="PERSON">
<id name="key" column="personKey">
<generator class="native"/>
</id>
<timestamp name="Ts" column="ts" source="vm"/>
<property name="Id" type="string" column="id" length="128"/>
<property name="FirstName" type="string" column="firstName" length="80"/>
<property name="LastName" type="string" column="lastName" length="80"/>
<many-to-one name="Location"
column="locationKey"
class="Location"
not-null="true"
/>
</class>
Code between sessionFactory.openSession() and session.close():Code:
// retrieve Location record(s)
Transaction tx = session1.beginTransation();
List objs = session1.createQuery("from Location").list()
tx.commit();
// Only one Location in DB. now retrieve Persons
Iterator<Person> itr = location.getClients().iterator();
while (itr.hasNext()) {
Person p = itr.next();
Hibernate.intialize(p);
}
// evict top of graph -- cascades down to remainder of graph
Transaction tx = session1.beginTransation();
session1.evict (location);
tx.commit();
// create new session factory and open session into 'session2'.
// then replicate the graph
Transaction tx = session2.beginTransaction();
session2.replicate();
tx.commit();
// close it all down.
Name and version of the database you are using:MySQL 5.0.27 and HSQLDB
The generated SQL (show_sql=true):When I have logging set to 'org.hibernate=info', I see the following:
Code:
[java] Hibernate: select ts from LOCATION where locationKey =?
[java] Hibernate: insert into LOCATION (locationKey, ts, name, id, description, addressKey) values (null, ?, ?, ?, ?, ?)
[java] Hibernate: call identity()
[java] Hibernate: select ts from PERSON where personKey =?
[java] Hibernate: insert into PERSON (personKey, ts, id, firstName, lastName, gender, email, phone, dob, lastSynch, locationKey, addressKey) values (null, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
[java] Hibernate: call identity()
[java] Hibernate: select ts from PERSON where personKey =?
[java] Hibernate: update PERSON set ts=?, id=?, firstName=?, lastName=?, gender=?, email=?, phone=?, dob=?, lastSynch=?, locationKey=?, addressKey=? where personKey=? and ts=?
Now, when I have logging set to 'org.hibernate=debug', I see the following:
Code:
[java] Hibernate: select ts from LOCATION where locationKey =?
[java] Hibernate: insert into LOCATION (locationKey, ts, name, id, description, addressKey) values (null, ?, ?, ?, ?, ?)
[java] Hibernate: call identity()
[java] Hibernate: select ts from PERSON where personKey =?
[java] Hibernate: insert into PERSON (personKey, ts, id, firstName, lastName, gender, email, phone, dob, lastSynch, locationKey, addressKey) values (null, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
[java] Hibernate: call identity()
[java] Hibernate: select ts from PERSON where personKey =?
[java] Hibernate: insert into PERSON (personKey, ts, id, firstName, lastName, gender, email, phone, dob, lastSynch, locationKey, addressKey) values (null, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
[java] Hibernate: call identity()
See the two inserts into PERSON?
Wha?