I was trying to set up a parent-child (one-to-many) relationship
with a cascade down to the children. It's essentially the same as the
relationship between User and Bid as in the example with the addition
of a version column. However, when I go to save the parent, Hibernate
tries to update the children, including incrementing the version number,
even though no change was made to them and then it throws a
StaleObjectStateException.
I only included the portion of the log after the call to Session.flush().
Let me know if you need more.
Any ideas as to what is wrong with my mappings?
thanks,
-r
p.s. I was trying to determine if Hibernate considered a change to
the contents of the set of children as a change to the parent and
incremented the version number accordingly. If so, would it also consider
a change to one of the elements, i.e., one of the children, would it also
consider that a change to the parent. I'd like to get this working,
but if someone could tell me what Hibernate's behavior is in that case,
it'd be almost as good.
Hibernate version:
2.1.6
Mapping documents:
<hibernate-mapping>
<class name="scratch.Child" table="child" dynamic-update="false"
dynamic-insert="false" >
<id name="id" column="id" type="java.lang.Integer">
<generator class="assigned">
</generator>
</id>
<version name="version" type="int" column="version" access="property"
unsaved-value="undefined"
/>
<property name="name" type="java.lang.String" update="true"
insert="true" access="property" column="name" length="64"
not-null="true" />
<many-to-one name="parent" class="scratch.Parent" cascade="none"
outer-join="auto" update="true" insert="true"
access="property" column="parent_id" />
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="scratch.Parent" table="parent" dynamic-update="false"
dynamic-insert="false" >
<id name="id" column="id" type="java.lang.Integer">
<generator class="assigned"></generator>
</id>
<version name="version" type="int" column="version" access="property"
unsaved-value="undefined"/>
<property name="name" type="java.lang.String" update="true"
insert="true" access="property" column="name" length="64"
not-null="true"/>
<set name="children" lazy="false" inverse="true"
cascade="all" sort="unsorted" >
<key column="parent_id"></key>
<one-to-many class="scratch.Child" />
</set>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():
Parent parent = new Parent(1, "parent");
parent.addChild(new Child(1, "child1", parent));
parent.addChild(new Child(2, "child2", parent));
Session session = sessionFactory.openSession();
Transaction currentTransaction = session().beginTransaction();
Serializable id = session.save(object);
System.out.println(session.get(clazz, id));
session().flush();
currentTransaction.commit();
session.closeSession();
Full stack trace of any exception that occurs:
net.sf.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) for scratch.Child instance with identifier: 2
at net.sf.hibernate.persister.AbstractEntityPersister.check(AbstractEntityPersister.java:506)
at net.sf.hibernate.persister.EntityPersister.update(EntityPersister.java:687)
at net.sf.hibernate.persister.EntityPersister.update(EntityPersister.java:642)
at net.sf.hibernate.impl.ScheduledUpdate.execute(ScheduledUpdate.java:52)
at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2418)
at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2372)
at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2240)
at scratch.HibTest.tearDown(HibTest.java:54)
at junit.framework.TestCase.runBare(TestCase.java:130)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:421)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:305)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:186)
Name and version of the database you are using:
MySql v. 4.1.3
Debug level Hibernate log excerpt:
2004-08-12 22:25:48,048 [] DEBUG SessionImpl -resolved object in session cache [scratch.Parent#1]
2004-08-12 22:25:48,048 [] INFO BaseHibernateDao -<<< createObject
2004-08-12 22:25:48,048 [] DEBUG SessionImpl -flushing session
2004-08-12 22:25:48,048 [] DEBUG Cascades -processing cascades for: scratch.Parent
2004-08-12 22:25:48,048 [] DEBUG Cascades -cascading to collection: scratch.Parent.children
2004-08-12 22:25:48,048 [] DEBUG Cascades -cascading to saveOrUpdate()
2004-08-12 22:25:48,048 [] DEBUG SessionImpl -saveOrUpdate() persistent instance
2004-08-12 22:25:48,048 [] DEBUG Cascades -cascading to saveOrUpdate()
2004-08-12 22:25:48,048 [] DEBUG SessionImpl -saveOrUpdate() persistent instance
2004-08-12 22:25:48,048 [] DEBUG Cascades -done processing cascades for: scratch.Parent
2004-08-12 22:25:48,048 [] DEBUG SessionImpl -Flushing entities and processing referenced collections
2004-08-12 22:25:48,058 [] DEBUG SessionImpl -Collection found: [scratch.Parent.children#1], was: [<unreferenced>]
2004-08-12 22:25:48,058 [] DEBUG SessionImpl -Updating entity: [scratch.Child#2]
2004-08-12 22:25:48,058 [] DEBUG Versioning -Incrementing: 0 to 1
2004-08-12 22:25:48,058 [] DEBUG SessionImpl -Updating entity: [scratch.Child#1]
2004-08-12 22:25:48,058 [] DEBUG Versioning -Incrementing: 0 to 1
2004-08-12 22:25:48,058 [] DEBUG SessionImpl -Processing unreferenced collections
2004-08-12 22:25:48,058 [] DEBUG SessionImpl -Scheduling collection removes/(re)creates/updates
2004-08-12 22:25:48,058 [] DEBUG SessionImpl -Flushed: 1 insertions, 2 updates, 0 deletions to 3 objects
2004-08-12 22:25:48,058 [] DEBUG SessionImpl -Flushed: 1 (re)creations, 0 updates, 0 removals to 1 collections
2004-08-12 22:25:48,058 [] DEBUG Printer -listing entities:
2004-08-12 22:25:48,068 [] DEBUG Printer -scratch.Child{name=child2, parent=Parent#1, id=2, version=0}
2004-08-12 22:25:48,068 [] DEBUG Printer -scratch.Child{name=child1, parent=Parent#1, id=1, version=0}
2004-08-12 22:25:48,068 [] DEBUG Printer -scratch.Parent{name=parent, children=[Child#2, Child#1], id=1, version=0}
2004-08-12 22:25:48,068 [] DEBUG SessionImpl -executing flush
2004-08-12 22:25:48,068 [] DEBUG EntityPersister -Inserting entity: [scratch.Parent#1]
2004-08-12 22:25:48,068 [] DEBUG EntityPersister -Version: 0
2004-08-12 22:25:48,068 [] DEBUG BatcherImpl -about to open: 0 open PreparedStatements, 0 open ResultSets
2004-08-12 22:25:48,068 [] DEBUG SQL -insert into parent (version, name, id) values (?, ?, ?)
Hibernate: insert into parent (version, name, id) values (?, ?, ?)
2004-08-12 22:25:48,068 [] DEBUG BatcherImpl -preparing statement
2004-08-12 22:25:48,078 [] DEBUG EntityPersister -Dehydrating entity: [scratch.Parent#1]
2004-08-12 22:25:48,078 [] DEBUG IntegerType -binding '0' to parameter: 1
2004-08-12 22:25:48,078 [] DEBUG StringType -binding 'parent' to parameter: 2
2004-08-12 22:25:48,078 [] DEBUG IntegerType -binding '1' to parameter: 3
2004-08-12 22:25:48,078 [] DEBUG BatcherImpl -Adding to batch
2004-08-12 22:25:48,078 [] DEBUG BatcherImpl -Executing batch size: 1
2004-08-12 22:25:48,078 [] DEBUG BatcherImpl -done closing: 0 open PreparedStatements, 0 open ResultSets
2004-08-12 22:25:48,078 [] DEBUG BatcherImpl -closing statement
2004-08-12 22:25:48,078 [] DEBUG EntityPersister -Updating entity: [scratch.Child#2]
2004-08-12 22:25:48,078 [] DEBUG EntityPersister -Existing version: 0 -> New version: 1
2004-08-12 22:25:48,078 [] DEBUG BatcherImpl -about to open: 0 open PreparedStatements, 0 open ResultSets
2004-08-12 22:25:48,078 [] DEBUG SQL -update child set version=?, name=?, parent_id=? where id=? and version=?
Hibernate: update child set version=?, name=?, parent_id=? where id=? and version=?
2004-08-12 22:25:48,078 [] DEBUG BatcherImpl -preparing statement
2004-08-12 22:25:48,078 [] DEBUG EntityPersister -Dehydrating entity: [scratch.Child#2]
2004-08-12 22:25:48,078 [] DEBUG IntegerType -binding '1' to parameter: 1
2004-08-12 22:25:48,078 [] DEBUG StringType -binding 'child2' to parameter: 2
2004-08-12 22:25:48,078 [] DEBUG IntegerType -binding '1' to parameter: 3
2004-08-12 22:25:48,078 [] DEBUG IntegerType -binding '2' to parameter: 4
2004-08-12 22:25:48,078 [] DEBUG IntegerType -binding '0' to parameter: 5
Query "insert into parent (version, name, id) values (0, 'parent', 1)" execution time: 0
Query "update child set version=1, name='child2', parent_id=1 where id=2 and version=0" execution time: 10
2004-08-12 22:25:48,088 [] WARN StaleObjectStateException -An operation failed due to stale data
|