Hibernate Books

All times are UTC - 5 hours [ DST ]



Post new topic Reply to topic  [ 5 posts ] 
Author Message
 Post subject: Problems with one-to-many with cascade
PostPosted: Fri Aug 13, 2004 2:14 am 
Beginner
Beginner

Joined: Mon Aug 09, 2004 3:35 pm
Posts: 22
Location: Minneapolis, MN, USA
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


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 13, 2004 2:51 am 
Expert
Expert

Joined: Thu Jan 29, 2004 2:31 am
Posts: 362
Location: Switzerland, Bern
cascade=all can not be used with assigned identifiers because it implicitely calls saveOrUpdate().

If you can either
- use a generated identifier
- specify an appropriate unsave-value in the id tag.
- specify unsaved-value="null" for the version and make sure the JAVA property is an Integer and not an int
- implement the Interceptor method isUnsaved for the Child class.

HTH
Ernst


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 13, 2004 8:40 am 
Beginner
Beginner

Joined: Mon Aug 09, 2004 3:35 pm
Posts: 22
Location: Minneapolis, MN, USA
Thanks, Ernst. Option C (Integer version and unsaved-value-null) fixed it.

-r


Top
 Profile  
 
 Post subject:
PostPosted: Sun Aug 15, 2004 12:03 am 
Newbie

Joined: Fri Aug 13, 2004 4:11 pm
Posts: 5
Location: Houston, TX
I could revert back to whatever I was doing, but probably something stupid that was keeping it from working. The bigger problem is that even if it did work, I can't add another column in the table and field in the class for versioning just to make the cascading work. Is there any other way for cascading to work with an assigned identifier?

Thanks,
David


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 15, 2008 7:34 am 
Beginner
Beginner

Joined: Wed Aug 22, 2007 5:53 am
Posts: 38
I have the opposite problem :

I have 2 classes Slip and Rcpt having many-to-one relationship (Slip can have many receipts)...

Receipt is saved first (without Slip_NO)

Then i create a Slip and associate the Receipt with it...

Then i try to save the Slip.. It inserts Slip record... It also Inserts another receipt record in Receipt table.. (instead of updating the previous receipt record)

I am using
<set name="rcpts" inverse="true" cascade="save-update">
<key>
<column name="RECEIPT_ID" not-null="true" unique="true" />
</key>
<one-to-many class="Rcpt" />
</set>


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.