Hibernate version: 3.2.0.GA
Database: MySQL 5.0.27
Hello
I have an entity (let's call it Person) with a One-To-One relationship to another entity (Address) which has cascade-all specified.
Both entities have a Primary Key which is an int.
The Person entity also has accountSystem and accountNumber attributes. The accountNumber attribute is randomly generated and assigned at the time of persistence. The bones of this process are as follows:
Code:
public void save( Person person ) {
EntityManager mgr;
EntityTransaction txn;
boolean retryRequired;
//Initialise:-
em = .....
em.setFlushMode( FlushModeType.COMMIT );
txn = em.getTransaction();
txn.begin();
retryRequired = false;
try {
if( person.getId() == 0 ) {
//New person - assign an account number and insert:-
person.setAccountNumber( getRandomAccountNumber() );
em.persist( person );
... do some other stuff ...
} else {
//Update existing person:-
em.merge( person );
}
txn.commit();
} catch( Exception x ) {
txn.rollback();
//Retry if the error was due to an account-number collision:-
if( exceptionCausedByEntityExistsException(x) ) {
retryRequired = true;
}
} finally {
em.close();
}
//Retry if the error was due to an account-number collision:-
if( retryRequired ) {
warning( "Insert of person failed due to duplicate account number - retrying..." );
save( person );
}
}
The Person entity is declared as follows in orm.xml - note there's a unique constraint on the accountNumber and accountSystem attributes:-
Code:
<entity class="x.y.z.Person" access="FIELD">
<table name="Person">
<unique-constraint>
<column-name>accountNumber</column-name>
<column-name>accountSystem</column-name>
</unique-constraint>
</table>
<attributes>
<id name="id">
<generated-value strategy="AUTO" />
</id>
<basic name="username" optional="false" />
[snip]
<basic name="accountSystem" optional="false" />
<basic name="accountNumber" optional="false" />
<one-to-one name="address" target-entity="x.y.z.Address" fetch="LAZY" optional="false">
<cascade>
<cascade-all />
</cascade>
</one-to-one>
</attributes>
</entity>
There's nothing out of the ordinary in Address's declaration.
When I execute the program in order to create a bunch of new Persons, it all works great. I call save(new Person(...)) a number of times and each is saved along with their address details (due to cascade-all) and their unique random account numbers.
However, in order to test my exception handling, I temporarily modified my getRandomAccountNumber() method in order to always return 123. I ran the program again and the first Person is inserted successfully as before. The second Person's insert then fails, I get the warning message informing me that the a collision occured and a retry is about to take place. All as expected so far... except I then get a PersistenceException:
Code:
org.hibernate.PersistentObjectException: detached entity passed to persist: x.y.z.Address
I don't understand why the Address has become detached during the retry. Is this expected given the code above? If so, why is it attached the first time through? I thought by performing a rollback I'd cleaned up properly and subsequent passes through the save() method would exhibit the same behaviour as the first.
Many thanks in advance for any advice anyone is able to offer.
Darren