-->
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.  [ 4 posts ] 
Author Message
 Post subject: Merge of detached object with bad id causes insert?
PostPosted: Sun Sep 11, 2005 2:56 am 
Newbie

Joined: Tue Jun 07, 2005 3:42 pm
Posts: 5
In setting up some unit tests for my DAO, I came across strange behavior in Session#merge(). It appears that merging a detached object which has a non-existent primary key (where normally the keys are "natively" generated) causes the row to be inserted, ignoring the bogus primary key. Has anyone else noticed this behavior?

This is undesirable since it could cause rows to be inserted where an update was intended. This could happen if the target row was concurrently deleted in another session, or if the id in the detached object being merged was somehow corrupted.

Hibernate version: 3.0.5

Mapping documents:

<hibernate-mapping package="testutils.widget">
<class name="Widget" table="WIDGETS" lazy="false">
<id name="id" type="java.lang.Long" column="WIDGET_ID">
<generator class="native"/>
</id>
<property name="name">
<column name="WIDGET_NAME" not-null="true" unique="true"/>
</property>
<property name="description">
<column name="WIDGET_DESC"/>
</property>
</class>

Code between sessionFactory.openSession() and session.close():

String w1Name = "foo";
String w1Desc = "a test widget";
Widget w1 = new Widget(w1Name,w1Desc);
w1.setId(2718281L); // setting nonexistent primary key for test
Transaction tx = session.beginTransaction();
session.merge(w1); // row is inserted but with generated id
tx.commit();

Name and version of the database you are using: HSQLDB 1.0ea4

The generated SQL (show_sql=true):

Hibernate: select widget0_.WIDGET_ID as WIDGET1_0_, widget0_.WIDGET_NAME as WIDGET2_0_0_, widget0_.WIDGET_DESC as WIDGET3_0_0_ from WIDGETS widget0_ where widget0_.WIDGET_ID=?
Hibernate: insert into WIDGETS (WIDGET_NAME, WIDGET_DESC, WIDGET_ID) values (?, ?, null)
Hibernate: call identity()

Debug level Hibernate log excerpt:

opened session at timestamp: 4613822072254464
begin
opening JDBC connection
current autocommit status: true
disabling autocommit
id unsaved-value: null
detached instance of: testutils.widget.Widget
merging detached instance
loading entity: [testutils.widget.Widget#2718281]
attempting to resolve: [testutils.widget.Widget#2718281]
object not resolved in any cache: [testutils.widget.Widget#2718281]
Materializing entity: [testutils.widget.Widget#2718281]
loading entity: [testutils.widget.Widget#2718281]
about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
select widget0_.WIDGET_ID as WIDGET1_0_, widget0_.WIDGET_NAME as WIDGET2_0_0_, widget0_.WIDGET_DESC as WIDGET3_0_0_ from WIDGETS widget0_ where widget0_.WIDGET_ID=?
Hibernate: select widget0_.WIDGET_ID as WIDGET1_0_, widget0_.WIDGET_NAME as WIDGET2_0_0_, widget0_.WIDGET_DESC as WIDGET3_0_0_ from WIDGETS widget0_ where widget0_.WIDGET_ID=?
preparing statement
binding '2718281' to parameter: 1
about to open ResultSet (open ResultSets: 0, globally: 0)
processing result set
done processing result set (0 rows)
about to close ResultSet (open ResultSets: 1, globally: 1)
about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
closing statement
total objects hydrated: 0
initializing non-lazy collections
done entity load
merging transient instance
saving [testutils.widget.Widget#<null>]
executing insertions
Inserting entity: testutils.widget.Widget (native id)
about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
insert into WIDGETS (WIDGET_NAME, WIDGET_DESC, WIDGET_ID) values (?, ?, null)
Hibernate: insert into WIDGETS (WIDGET_NAME, WIDGET_DESC, WIDGET_ID) values (?, ?, null)
preparing statement
Dehydrating entity: [testutils.widget.Widget#<null>]
binding 'foo' to parameter: 1
binding 'a test widget' to parameter: 2
about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
closing statement
about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
call identity()
Hibernate: call identity()
preparing statement
Natively generated identity: 1
about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
closing statement
commit
automatically flushing session
flushing session
processing flush-time cascades
dirty checking collections
Flushing entities and processing referenced collections
Processing unreferenced collections
Scheduling collection removes/(re)creates/updates
Flushed: 0 insertions, 0 updates, 0 deletions to 1 objects
Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
listing entities:
testutils.widget.Widget{description=a test widget, name=foo, id=1}
executing flush
post flush
before transaction completion
before transaction completion
re-enabling autocommit
committed JDBC Connection
after transaction completion
after transaction completion
closing session
closing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
after transaction completion
after transaction completion


Top
 Profile  
 
 Post subject: Re: Merge of detached object with bad id causes insert?
PostPosted: Sun Sep 11, 2005 3:04 am 
Expert
Expert

Joined: Mon Jul 04, 2005 5:19 pm
Posts: 720
hiendohar wrote:
It appears that merging a detached object which has a non-existent primary key ... causes the row to be inserted



the API wrote:
If the given instance is unsaved, save a copy of and return it as a newly persistent instance.


Top
 Profile  
 
 Post subject: Re: Merge of detached object with bad id causes insert?
PostPosted: Sun Sep 11, 2005 1:43 pm 
Newbie

Joined: Tue Jun 07, 2005 3:42 pm
Posts: 5
Thanks, Dennis, but I don't think that applies here.

By "unsaved" I understand transient, as indicated by the "unsaved-value" (null in my case).

When the id is the unsaved value, I would expect for a row to be inserted as the API indicates. Indeed, it does just that.

The problem here is that an id is supplied, indicating that the object is detached, not transient. The id is silently ignored -- as if it were the unsaved value.

dennisbyrne wrote:
hiendohar wrote:
It appears that merging a detached object which has a non-existent primary key ... causes the row to be inserted



the API wrote:
If the given instance is unsaved, save a copy of and return it as a newly persistent instance.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 15, 2005 6:11 pm 
Beginner
Beginner

Joined: Tue Jun 14, 2005 12:14 pm
Posts: 37
This is the expected behavior of merge():

* if there is a persistent instance with the same identifier currently associated with the session, copy the state of the given object onto the persistent instance
* if there is no persistent instance currently associated with the session, try to load it from the database, or create a new persistent instance
* the persistent instance is returned
* the given instance does not become associated with the session, it remains detached


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