EM Find behaves differently if Entity removed within same transaction - java

It seems that the Hibernate EntityManager find method behaves differently in the following two cases:
Case 1 - Entity does not exist in the database before transaction starts. Within transaction, find of the entity returns null.
Case 2 - Entity exists in DB before transaction. Within transaction, entity is remove'd, then a find of the same key throws EntityNotFoundException.
Is this expected behaviour? Do I need to do a flush before the find for it to behave the same?

It is unexpected that find method in EntityManager throws EntityNotFoundException when entity is not found. Documentation is quite clear:
Returns:
the found entity instance or null if the entity does not exist
This bug was reported in HHH-7861. It is fixed in 4.1.10, which is not yet released.

OK, answering the second part of my question, it seems that a flush between the remove and the find in case 2 makes it behave the same as case 1. That is, the find just returns null without throwing an exception (which is what we want, as the exception triggers a rollback).
Answer points will go to anyone who can tell me why the find should behave differently.

Related

The right way to verify that javax.persistence.EntityManager.remove(Object entity) actually removed the entity

We are converting from EJB2 to EJB3 plus JPA.
The EJB2 EntityBean's ejbremove method throws a javax.ejb.RemoveException
Whereas the Javax.Persistence.EntityManager.remove throws only an IllegalArgumentException and a TransactionRequiredException none of which speaks to whether the entity was removed or not (or so I glean from the javadocs)
So how can I verify that whatever it was that would have generated a RemoveException did not happen in the execution of the EntityManager.remove()
I suppose I could save the primary key of the object before trying to remove it and searching for it afterwards and verifying that it isn't in fact there, but that's round about and I suspect I'm simply missing something obvious.

Persisting a preexisting Entity Instance is ignored by the persist operation [duplicate]

This question already has answers here:
What are the differences between the different saving methods in Hibernate?
(10 answers)
Closed 7 years ago.
I was going through the JPA 2 specification and found two statements that sounds contradictory to me.
"If X is a preexisting managed entity, it is ignored by the persist operation." - Pg 76
"The EntityExistsException may thrown by the persistence provider when the persist operation is invoked and the entity already exists." - Pg 129
The statement 1 says something that sounds different from statement 2. So, my question is what is the difference between "preexisting managed entity" and "entity already exists"?
In version 2.1 of the spec, chapter 3.2.2, you can find this about the persist() operation:
If X is a preexisting managed entity, it is ignored by the persist operation. However, the persist operation is cascaded to entities referenced by X, if the relationships from X to these other entities are annotated with the cascade=PERSIST or cascade=ALL annotation element value or specified with the equivalent XML descriptor element.
If X is a removed entity, it becomes managed.
If X is a detached object, the EntityExistsException may be thrown when the persist operation is invoked, or the EntityExistsException or another PersistenceException may be thrown at flush or commit time
So, persist() will ignore the entity if it's a managed object. It can throw an exception (or throw it, or another one, later) if the entity is a detached object.
First case:
Foo foo = em.find(Foo.class, 1L);
em.persist(foo); // ignored
Second case:
Foo foo = new Foo();
foo.setId(1L);
em.persist(foo); // may throw an exception

how to check if record exists using hibernate

I am new to hibernate. I am trying to implement a business rule where i need to check if a record exists in the database to continue different path based on the existance /not.
I am trying to ask if there is a light weight way to see if a record exists in database.
please point me to the documentation if there are some available.
Thanks for reading
When you know the primary key value, please take a look at EntityManager#find (http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#find(java.lang.Class,java.lang.Object).
More lightweight solution is use:
getReference
<T> T getReference(java.lang.Class<T> entityClass,
java.lang.Object primaryKey)
Get an instance, whose state may be lazily fetched. If the requested
instance does not exist in the database, the EntityNotFoundException
is thrown when the instance state is first accessed. (The persistence
provider runtime is permitted to throw the EntityNotFoundException
when getReference is called.)
getReference method are not required to be invoked within a transaction context

JPA: lazy load slick moment

As I understand, lazyLoadedObject in JPA might be not loaded even after using of it getter method. So in example below, after stroke 1, lazilyLoadededPerson might be still null, and only after stroke 2 the container will run the query to the db.
lazilyLoadedPerson = runQueryToLoadPerson();
lazilyLoadedPerson.getName();
My question is: Does the code below contain an error in stroke 2?
lazilyLoadedPerson = runQueryToLoadPerson();
if (lazilyLoadedPerson != null) { //if lazilyLoadedPerson == null suppose that such person doesn't exists in database
return lazilyLoadedPerson.getName();
}
Why I consider that it will be an error:
after the stroke 1 in the example above, the lazilyLoadedPerson will be null even the lazilyLoadedPerson exists in the database. We have the situation when the entity exists in the database but the getName() method will be never invoked.
Short answer
A lazily loaded object is never null.
Longer answer
The explanation is valid for Hibernate but other JPA-providers should be similar. See the official documentation for a detailed explanation of how lazy loading works or this short article for a short one. But the core facts are:
If for some reason or another Hibernate decides to lazily load an object, you don't get the object you wanted but a proxy to that object instead (i.e. not a null-reference). As soon as you call something on that proxy that can only be known by accessing the database, the proxy does exactly that. Provided you have an active session (and some other conditions are met) Hibernate executes the necessary query and the call returns.
Your Example
Let's take your example and extend it with a declaration
MyPerson lazilyLoadedPerson = runQueryToLoadPerson();
if (lazilyLoadedPerson != null) { //if lazilyLoadedPerson == null suppose that such person doesn't exists in database
return lazilyLoadedPerson.getName();
}
Assuming you did not define a proxy class for the class MyPerson, Hibernate has no other option but to actually load the object you wanted from the database. One of the reasons is exactly what you're doing: if it would return null, you could not check, whether the object even exists in the database.
Advice
Worrying about lazy loading can be quite confusing at the beginning. My advice is, not to do that too early. If you're just getting to know JPA, simply annotate all Collections with fetch = FetchType.EAGER and don't define any proxies and you'll never come across lazy loading.
If you got to know the whole concept a little better, you can read up on lazy loading and change your xml-file or annotation accordingly.

Tips for resolving Hibernate/JPA EntityNotFoundException

I'm running into a problem with Hibernate where when trying to delete a group of Entities I encounter the following error:
javax.persistence.EntityNotFoundException: deleted entity passed to persist: [com.locuslive.odyssey.entity.FreightInvoiceLine#<null>]
These are not normally so difficult to track down as they are usually caused by an entity being deleted but not being removed from a Collection that it is a member of.
In this case I have removed the entity from every list that I can think of (it's a complex datamodel). I've put JBoss logging into Trace and I can see the collections that are being cascaded. However I can't seem to find the Collection containing the entity that I'm deleting.
Does anyone have any tips for resolving this particular Exception? I'm particularly looking for ways to identify what might be the owning Collection.
Thanks.
Finally found it, and it's exactly the sort of frustrating "find the list" that I had expected.
The code that was performing the delete was extending Seam's EntityHome.
public class FreightInvoiceHome extends EntityHome<FreightInvoice> {
public void deleteLine(FreightInvoiceLine freightInvoiceLine) {
getEntityManager().remove(freightInvoiceLine);
freightInvoiceLine.getShipInstrLineItem().getFreightInvoiceLines().remove(freightInvoiceLine);
/* These next two statements are effectively performing the same action on the same FreightInvoice entity
* If I use the first one then I get the exception. If I use the second one then all is ok.
*/
getInstance().getFreightInvoiceLines().remove(freightInvoiceLine);
//freightInvoiceLine.getFreightInvoice().getFreightInvoiceLines().remove(freightInvoiceLine);
}
}
I had suspected that this might have been caused by a dodgy equals() / hashcode() but after replacing both there is no difference.
Happy to change the accepted to someone else if they can explain the difference between the two.
I would suggest doing the
getEntityManager().remove(freightInvoiceLine);
as the last step. I think it is a good practice, first to remove the child from any collections and then actually delete it. It will save headaches in many cases.

Categories