-->
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.  [ 5 posts ] 
Author Message
 Post subject: Primary Key being set when statement fails.
PostPosted: Fri Apr 14, 2006 5:42 pm 
Newbie

Joined: Thu Jul 14, 2005 5:39 pm
Posts: 12
Location: Ann Arbor, MI
Heya.

I'm testing an integration testcase (using Spring's AbstractTransactionalDataSourceSpringContextTests class) where I'm creating an Address object and setting its not-null properties one-by-one, testing that it won't save if I've left a not-null field as null.

I was surprised by the following behavior:

Code:
...
Address address = new Address();
address.setStreetAddress1("Street 1");

try {
  this.addressDAO.saveOrUpdate(address);
  this.addressDAO.flush();
  // Since not-null city, state, and zipCode haven't been set, failure.
  fail();
} catch (Exception e) { e.printStackTrace(); }
assertNull("Expected a NULL id but instead found: " + address.getId(), address.getId());
...


As expected, an exception was thrown and printed out complaining about not-null properties that were null.

However, what wasn't expected was the assertion failure, with the message: "Expected a null id but instead found: 1"

It is my understanding that Hibernate defines a persistent object to be one whose ID-property is not null; I would expect the object's ID-property to be left null if the save did not go through.

I do understand that I'm swallowing an exception, but in the context of this test, I think it's reasonable -- the rationale is to keep trying to insert it, fixing one property at a time. But since the ID is being set, Hibernate then thinks I'm doing an update, which ultimately fails when all the not-null properties are set because there's no row to update. I can't set the id to null manually, as Hibernate then complains.

I guess I'm curious as to the rationale behind setting the primary key even when the insertion fails.

Thanks,
Jim


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 14, 2006 8:11 pm 
Regular
Regular

Joined: Wed Jul 07, 2004 2:00 pm
Posts: 64
I can come up with one example. I recently had to work with Hibernate Interceptors. In my case, I used it to set the value of a couple of properties when Hibernate is going to insert or update an entity. One of these properties is also mapped as not-null. This means that the null checking would have to happen after the interceptor is called. Other people, though, use interceptors for doing things like auditing. In order to do this, the primary key for the entity must be already assigned before the interceptor is called. Thus, the PK must be set before the null check is done.

I'm sure that other people can come up with many other reasons.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 14, 2006 10:11 pm 
Newbie

Joined: Thu Jul 14, 2005 5:39 pm
Posts: 12
Location: Ann Arbor, MI
I get needing to set the primary key before an insert/update, but I still don't understand not returning the object to a useful state if something goes wrong with the insert/update and an exception is thrown. It's kind of like not rolling back a transaction, in my opinion.

While I'm using a credit, since checking the primary key in this situation is out, how can I determine whether an object was actually made persistent or not? For my test above, I'm resorting to:

Code:
assertNotNull(this.addressDAO.findById(address.getId()));


But I suspect that Hibernate's done something to the proxy-object that I can check without having to go back to the database. I'll check the API.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Apr 15, 2006 12:07 am 
Regular
Regular

Joined: Wed Jul 07, 2004 2:00 pm
Posts: 64
Well, if this is a JUnit test, why do you care what the ID is at the point you do the AssertNull - this is successful completion of the unit test.

In production, the Hibernate doc recommends that the session be dropped. The state of the entities that you tried to save are also unstable. For example, lets say that you have a Person with a collection of Phones. You forget to set a not-null property in a Phone. In a transaction, the Person and some of the other Phones may be saved before the not-null property error is thrown. As a result, the PK on the person and all previous Phones are already set, but the transaction was rolled back. This is the problem that you have observed. But there is another problem. Any properties set by an Interceptor or the event system will also still be set. I guess the Hibernate guys just decided that it wasn't worth making a copy of the entities that you pass to Hibernate methods for a 'memory transaction' to be rolled back when the database transaction rolls back.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Apr 15, 2006 1:34 am 
Newbie

Joined: Thu Jul 14, 2005 5:39 pm
Posts: 12
Location: Ann Arbor, MI
I was going to continue on in the unit test, setting another not-null property after another, verifying that the insert would fail until they were all set. i.e. swallowing the exceptions and moving on.


I found what you were referring to, though:

"11.2.3. Exception handling
If the Session throws an exception (including any SQLException), you should immediately rollback the database transaction, call Session.close() and discard the Session instance. Certain methods of Session will not leave the session in a consistent state. No exception thrown by Hibernate can be treated as recoverable. Ensure that the Session will be closed by calling close() in a finally block."

Also clearly stated in the JavaDocs. Whups.


I appreciate your help,
Jim


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