I have a problem with the code snippet below regarding the JPA 1.0 spec. about merging entity :” If X is a removed entity instance, an IllegalArgumentException will be thrown by the merge operation (or the transaction commit will fail).”
The code sample :
Employee emp =new Employee("Paul",1500);//NEW
//em.flush(); //works as expected if uncommented
Employee managedEmp= em.merge(emp);//3- should throw IllegalArgumentException BUT NO
Additional informations :
This code execute within a stateless session bean’s method whith transaction attribute REQUIRED (in my case start a transaction)
The persistence context is transaction-scoped. Instance variable em references an injected entity manager
The Employee entity class as an id generated with the IDENTITY strategy (primary key created during the sql insertion when the transaction commits)
I’m using Glassfish Enterprise Server v2.1.1 ((v2.1 Patch06)(9.1_02 Patch12)), with Toplink essentials as persistence provider .
So my problem is that regarding the specification, the second call to merge on an entity in REMOVED state should throw IllegalArgumentException. If I use em.flush(), the behavior is the one expected : the exception is thrown. But without an explicit flush there is no exception.
But, if I have well understood the spec, when I call persist on a new instance, this instance becomes MANAGED (even if the id will be generated during insertion). When I call next remove() on the same instance, it becomes REMOVED. So the next call to merge() should throw IllegalArgumentException.
What can I have missed ? must I consider that my Employee instance is REALLY MANAGED only after the insertion in the database ? Is there a problem whith toplink essentials ?...
Hope I was enough clear. Thank you by advance
In case if you are still looking for the answer, found the following info
Just like persist, invoking remove on an entity does NOT cause an immediate SQL DELETE to be issued on the database. The entity will be deleted on the next invocation of EntityManager#flush() that involves that entity. This means that entities scheduled for removal can still be queried for and appear in query and collection results.
So, if explicit flush call is not invoked, the SQL queries will get queued up to be executed in bulk during the default flush that happens at the transaction commit time. And, there seems to be an order in which the SQL queries are fired on the database(atleast in case of hibernate.. more info at webpage.
Here, entity removal is executed last. The same might be happening in your scenario with TopLink as well.
its a good question, as you wrote:
"If X is a removed entity instance, an IllegalArgumentException will be thrown by the merge operation (or the transaction commit will fail)."
if it doesnt throw an IllegalArgumentException your transaction wont fail.
It's not strictly described by the specification.
the main goal is to prevent the database from illegal updates/inserts.
and in your case you dont have illegal updates/insterts
however it's strange..
eclipselink/toplink doesnt throw IllegalArgumentException, but hibernate does.
Although toplink is the IR, I think this time, Hibernate has a behaviour more in-phase with the specification.
I agree that sql order are deferred at the end of the transaction, but if I understood the spec, the IllegalArgumentException's throwing has more to do with entity's state than sql order because we can't exactly rely when the sql orders will be send. For me after calling remove(), the entity is in removed state, so it sh'ould be forbidden to call merge on it.
eclipselink's behaviour is ok by the spec.
but hibernate builds much better queries than openjpa/eclipselink.
we can choose from different implementations fortunately