-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 10 posts ] 
Author Message
 Post subject: NonUniqueObjectException occurs when saving a list
PostPosted: Fri Jul 30, 2004 6:48 am 
Newbie

Joined: Fri Jul 30, 2004 6:19 am
Posts: 5
Hi,

I am using Hibernate version 2.1.3 and I am having a problem when I try to add more than one object to a list and save it. There is no problem if I only add one BaseCodeListItem object to the list but when I create another object and add that to the list then do a saveOrUpdate I get a NonUniqueObjectException and I can't figure out why.

Thanks for your help.


MAPPING DOCUMENTS
CodeList.hbm.xml:
<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
<class
name="com.anite.monkey.om.codes.CodeList"
dynamic-update="false"
dynamic-insert="false"
>

<id
name="codeListId"
column="codeListId"
type="int"
>
<generator class="native">
</generator>
</id>

<discriminator
column="subclass"
type="string"
/>

<property
name="depth"
type="int"
update="true"
insert="true"
column="depth"
/>

<property
name="editableCodeList"
type="boolean"
update="true"
insert="true"
column="editableCodeList"
/>

<property
name="forumEditable"
type="boolean"
update="true"
insert="true"
column="forumEditable"
/>

<property
name="centreEditable"
type="boolean"
update="true"
insert="true"
column="centreEditable"
/>

<property
name="visibleCodeName"
type="java.lang.String"
update="true"
insert="true"
column="visibleCodeName"
/>

<list
name="codeListItems"
lazy="false"
inverse="false"
cascade="save-update"
>

<key
column="codeListId"
/>

<index
column="listPosition"
type="integer"
/>

<one-to-many
class="com.anite.monkey.om.codes.CodeListItem"
/>
</list>


<subclass
name="com.anite.monkey.om.events.FreeBusy"
dynamic-update="false"
dynamic-insert="false"
>
</subclass>

</class>

</hibernate-mapping>


CodeListItem.hbm.xml:
<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
<class
name="com.anite.monkey.om.codes.CodeListItem"
dynamic-update="false"
dynamic-insert="false"
>

<id
name="codeListItemId"
column="codeListItemId"
type="int"
>
<generator class="native">
</generator>
</id>

<property
name="value"
type="java.lang.String"
update="true"
insert="true"
column="value"
/>

<property
name="forumOwned"
type="boolean"
update="true"
insert="true"
column="forumOwned"
/>

<!--
To add non XDoclet property mappings, create a file named
hibernate-properties-CodeListItem.xml
containing the additional properties and place it in your merge dir.
-->

<joined-subclass
name="com.anite.monkey.om.codes.BaseCodeListItem"
dynamic-update="false"
dynamic-insert="false"
>
<key
column="codeListItemId"
/>

</joined-subclass>
<joined-subclass
name="com.anite.monkey.om.codes.CompositeCodeListItem"
dynamic-update="false"
dynamic-insert="false"
>
<key
column="codeListItemId"
/>

</joined-subclass>

</class>

</hibernate-mapping>


JAVA CODE
public void testInsert() throws HibernateException{
Transaction t = session.beginTransaction();
FreeBusy cl = new FreeBusy();
cl.setCentreEditable(CENTRE_EDITABLE);
cl.setDepth(DEPTH);
cl.setEditableCodeList(EDITABLE_CODE_LIST);
cl.setForumEditable(FORUM_EDITABLE);
cl.setVisibleCodeName(VISIBLE_CODE_NAME);

List cli = new ArrayList();
BaseCodeListItem b1 = new BaseCodeListItem();
b1.setValue("b1");
b1.setForumOwned(true);
cli.add( 0,b1);

//Problem occurs when this is included
BaseCodeListItem b2 = new BaseCodeListItem();
b2.setValue("b2");
b2.setForumOwned(true);
cli.add( 1,b2);
cl.setCodeListItems(cli);

session.saveOrUpdate(cl);

t.commit();

int key = cl.getCodeListId();
FreeBusy loadedCodeList = (FreeBusy) session.load(FreeBusy.class, new Integer(key));
assertEquals(key, loadedCodeList.getCodeListId());

}


STACK TRACE:

net.sf.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: 0, of class: com.anite.monkey.om.codes.BaseCodeListItem
at net.sf.hibernate.impl.SessionImpl.checkUniqueness(SessionImpl.java:1666)
at net.sf.hibernate.impl.SessionImpl.doUpdateMutable(SessionImpl.java:1435)
at net.sf.hibernate.impl.SessionImpl.doUpdate(SessionImpl.java:1462)
at net.sf.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:1385)
at net.sf.hibernate.engine.Cascades$4.cascade(Cascades.java:114)
at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:436)
at net.sf.hibernate.engine.Cascades.cascadeCollection(Cascades.java:526)
at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:452)
at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:503)
at net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:944)
at net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:850)
at net.sf.hibernate.impl.SessionImpl.saveWithGeneratedIdentifier(SessionImpl.java:768)
at net.sf.hibernate.impl.SessionImpl.save(SessionImpl.java:731)
at com.anite.monkey.om.events.FreeBusyTest.testInsert(FreeBusyTest.java:71)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
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)


DATABASE: HSQLdb-1.7.2-rc5


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 30, 2004 7:25 am 
Newbie

Joined: Fri Jul 30, 2004 6:19 am
Posts: 5
I have noticed that if I change the code to save after creating each object in the list and the list itself the test suceeds and everything is added as it should be to the database.

If I do not save each object explicitly they do not get inserted in the database. Is this the expected behaviour?

e.g.

public void testInsert() throws HibernateException{
Transaction t = session.beginTransaction();
FreeBusy cl = new FreeBusy();
cl.setCentreEditable(CENTRE_EDITABLE);
cl.setDepth(DEPTH);
cl.setEditableCodeList(EDITABLE_CODE_LIST);
cl.setForumEditable(FORUM_EDITABLE);
cl.setVisibleCodeName(VISIBLE_CODE_NAME);

List cli = new ArrayList();
BaseCodeListItem b1 = new BaseCodeListItem();
b1.setValue("b1");
b1.setForumOwned(true);
cli.add( 0,b1);
//added this to add the record to the codelistitem table
session.save(b1);
BaseCodeListItem b2 = new BaseCodeListItem();
b2.setValue("b2");
b2.setForumOwned(true);
//added this to add the record to the codelistitem table
session.save(b2);
cli.add( 1,b2);
cl.setCodeListItems(cli);

//added this so that the codelistid and listPosition get entered in the DB
//(without it those columns are left null)

session.saveOrUpdate(cl);

t.commit();

int key = cl.getCodeListId();
FreeBusy loadedCodeList = (FreeBusy) session.load(FreeBusy.class, new Integer(key));
assertEquals(key, loadedCodeList.getCodeListId());

}


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 30, 2004 8:32 am 
Expert
Expert

Joined: Fri Feb 06, 2004 7:49 am
Posts: 255
Location: Moscow, Russia
Quote:
net.sf.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: 0, of class: com.anite.monkey.om.codes.BaseCodeListItem

I see you use native ID generator, I am not sure where is the trouble, but test your code with manually assigned identifies for collection elements: <generator class="assigned"/>. It is not the best approach for real applications, but for test it is OK, maybe the trouble is inside native generator of your database, but I am not sure.

--
Leonid


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 30, 2004 9:42 am 
Newbie

Joined: Fri Jul 30, 2004 6:19 am
Posts: 5
Thanks for your help. I tried changing the generator to assigned and got a exception relating to stale data.

I think I have solved the problem now though just by adding

unsaved-value="any"

to the mapping for the id of the object I was trying to put in the list.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 30, 2004 9:59 am 
Expert
Expert

Joined: Fri Feb 06, 2004 7:49 am
Posts: 255
Location: Moscow, Russia
Den1se wrote:
I think I have solved the problem now though just by adding

unsaved-value="any"

to the mapping for the id of the object I was trying to put in the list.

Be sure that now you will have only SQL INSERTs for your objects, not more UPDATEs without tricks with life cycle or interceptor :)

About stale data... what stale data? you have not mapped <version > property or you have mapped it already.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 30, 2004 10:03 am 
Expert
Expert

Joined: Fri Feb 06, 2004 7:49 am
Posts: 255
Location: Moscow, Russia
shl wrote:
ot more UPDATEs without tricks with life cycle or interceptor :)

I think it is not the best solution in your case, try to solve NonUniqueObjectException trouble.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 30, 2004 10:44 am 
Newbie

Joined: Fri Jul 30, 2004 6:19 am
Posts: 5
I tried removing the unsaved-value="any" and now have a bi-directional one-to-many between the CodeList and the CodeListItem.
I try to run the test and get the following:


15:35:19,756 WARN PersistenceLocator:92 - Had to create a session as there wasn't one
Hibernate: insert into CodeList (depth, editableCodeList, forumEditable, centreEditable, visibleCodeName, subclass, codeListId) values (?, ?, ?, ?, ?, 'com.anite.monkey.om.events.FreeBusy', null)
Hibernate: CALL IDENTITY()
Hibernate: update CodeListItem set value=?, forumOwned=?, codeList=? where codeListItemId=?
15:35:24,383 ERROR StaleObjectStateException:27 - An operation failed due to stale data
net.sf.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) for com.anite.monkey.om.codes.BaseCodeListItem instance with identifier: 1
at net.sf.hibernate.persister.AbstractEntityPersister.check(AbstractEntityPersister.java:501)
at net.sf.hibernate.persister.NormalizedEntityPersister.update(NormalizedEntityPersister.java:693)
at net.sf.hibernate.persister.NormalizedEntityPersister.update(NormalizedEntityPersister.java:668)
at net.sf.hibernate.impl.ScheduledUpdate.execute(ScheduledUpdate.java:52)
at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2407)
at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2361)
at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2229)
at net.sf.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:61)
at com.anite.monkey.om.events.FreeBusyTest.testInsert(FreeBusyTest.java:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
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)
15:35:24,413 ERROR SessionImpl:2368 - Could not synchronize database state with session
net.sf.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) for com.anite.monkey.om.codes.BaseCodeListItem instance with identifier: 1
at net.sf.hibernate.persister.AbstractEntityPersister.check(AbstractEntityPersister.java:501)
at net.sf.hibernate.persister.NormalizedEntityPersister.update(NormalizedEntityPersister.java:693)
at net.sf.hibernate.persister.NormalizedEntityPersister.update(NormalizedEntityPersister.java:668)
at net.sf.hibernate.impl.ScheduledUpdate.execute(ScheduledUpdate.java:52)
at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2407)
at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2361)
at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2229)
at net.sf.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:61)
at com.anite.monkey.om.events.FreeBusyTest.testInsert(FreeBusyTest.java:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
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)

Looks like it is trying to update CodeListItem before it has been put into the database.


The stack trace is:

net.sf.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) for com.anite.monkey.om.codes.BaseCodeListItem instance with identifier: 1
at net.sf.hibernate.persister.AbstractEntityPersister.check(AbstractEntityPersister.java:501)
at net.sf.hibernate.persister.NormalizedEntityPersister.update(NormalizedEntityPersister.java:693)
at net.sf.hibernate.persister.NormalizedEntityPersister.update(NormalizedEntityPersister.java:668)
at net.sf.hibernate.impl.ScheduledUpdate.execute(ScheduledUpdate.java:52)
at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2407)
at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2361)
at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2229)
at net.sf.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:61)
at com.anite.monkey.om.events.FreeBusyTest.testInsert(FreeBusyTest.java:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
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)


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 30, 2004 10:55 am 
Expert
Expert

Joined: Fri Feb 06, 2004 7:49 am
Posts: 255
Location: Moscow, Russia
oops, as I got you use lilter int for identifiers:
Code:
int key = cl.getCodeListId();


put unsaved-value="0" or unsaved-value="-1" for all your mapped <id ..> elements.

in java code:
Code:
private int id = -1; // or 0

Better use long or
Quote:
For maximum flexibility, use java.lang.Long or java.lang.String.

[url]file:///home/shl/javalib/hibernate-2.1/doc/reference/en/html/best-practices.html[/url]

For java.lang.Long default unsaved-value (null) works fine :)

--
Leonid


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 30, 2004 10:58 am 
Expert
Expert

Joined: Fri Feb 06, 2004 7:49 am
Posts: 255
Location: Moscow, Russia
shl wrote:
[url]file:///home/shl/javalib/hibernate-2.1/doc/reference/en/html/best-practices.html[/url]

local link. http://www.hibernate.org/hib_docs/reference/en/html/best-practices.html

Better don't use literal types (int, long) for java identifiers.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 30, 2004 11:10 am 
Newbie

Joined: Fri Jul 30, 2004 6:19 am
Posts: 5
I had meant to change that. Thanks for pointing it out. I have changed the id value from an int and it works fine.

Thanks for your help.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 10 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.