You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@openjpa.apache.org by Heiko <it...@daimler.com> on 2010/04/14 15:11:02 UTC

EntityNotFoundException caused by EntityManager.refresh()

Hello,

in our Webservice-Application we use application managed persistence by
implementing entity managers via ThreadLocal to ensure there exists only a
single EntityManager at one time.

We have an Entity that is retrieved from the Database via em.find(). This
entity contains a OneToMany() relationship to a list of address objects,
with cascade set to REFRESH and fetch set lazy. Right after the find() is
done, a refresh() is issued on the object to make sure, it reflects the
actual state of the object in the database.

We now have the following problem. 

In case the base entity is request and the list of addresses is obtained
everything works fine. However, if externally by other systems accessing the
database, an address entry is deleted, and a subsequent call to the entity
is done, OpenJPA fails with the following exception:

&lt;openjpa-1.3.0-SNAPSHOT-r422266:831336 nonfatal store error&gt;
org.apache.openjpa.persistence.EntityNotFoundException: Diese Operation ist
für einige Instanzen fehlgeschlagen. Suchen Sie in den verschachtelten
Ausnahmen nach Einzelheiten.&#13;
	at
org.apache.openjpa.kernel.BrokerImpl.throwNestedExceptions(BrokerImpl.java:2356)&#13;
	at
org.apache.openjpa.kernel.BrokerImpl.refreshInternal(BrokerImpl.java:2885)&#13;
	at org.apache.openjpa.kernel.BrokerImpl.refresh(BrokerImpl.java:2778)&#13;
	at
org.apache.openjpa.kernel.DelegatingBroker.refresh(DelegatingBroker.java:1078)&#13;
	at
org.apache.openjpa.persistence.EntityManagerImpl.refresh(EntityManagerImpl.java:688)&#13;
	at
com.mbbank.pas.webservice.services.GetPersonHandler.handleGetPerson(GetPersonHandler.java:2965)&#13;
	at
net.corpds.emea.services.partner._64.wsdl.PartnerAccessServiceSoapBindingImpl.getPerson(PartnerAccessServiceSoapBindingImpl.java:105)&#13;
	at sun.reflect.GeneratedMethodAccessor65.invoke(Unknown Source)&#13;
	at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)&#13;
	at java.lang.reflect.Method.invoke(Method.java:618)&#13;
	at
org.apache.axis2.jaxws.server.dispatcher.JavaDispatcher.invokeTargetOperation(JavaDispatcher.java:70)&#13;
	at
org.apache.axis2.jaxws.server.dispatcher.JavaBeanDispatcher.invoke(JavaBeanDispatcher.java:97)&#13;
	at
org.apache.axis2.jaxws.server.EndpointController.invoke(EndpointController.java:100)&#13;
	at
org.apache.axis2.jaxws.server.JAXWSMessageReceiver.receive(JAXWSMessageReceiver.java:142)&#13;
	at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:375)&#13;
	at
org.apache.axis2.transport.http.HTTPTransportUtils.processHTTPPostRequest(HTTPTransportUtils.java:305)&#13;
	at
com.ibm.ws.websvcs.transport.http.WASAxis2Servlet.doPost(WASAxis2Servlet.java:921)&#13;
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:763)&#13;
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)&#13;
	at
com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1146)&#13;
	at
com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:593)&#13;
	at
com.ibm.ws.wswebcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:534)&#13;
	at
com.ibm.ws.webcontainer.servlet.CacheServletWrapper.handleRequest(CacheServletWrapper.java:90)&#13;
	at
com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:751)&#13;
	at
com.ibm.ws.wswebcontainer.WebContainer.handleRequest(WebContainer.java:1478)&#13;
	at
com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:126)&#13;
	at
com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:458)&#13;
	at
com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewInformation(HttpInboundLink.java:387)&#13;
	at
com.ibm.ws.http.channel.inbound.impl.HttpICLReadCallback.complete(HttpICLReadCallback.java:102)&#13;
	at
com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:165)&#13;
	at
com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)&#13;
	at
com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)&#13;
	at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:136)&#13;
	at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:196)&#13;
	at
com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:751)&#13;
	at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:881)&#13;
	at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1497)&#13;

The German error message corresponds to the following error code in the
English version I guess.

The instance of type "{0}" with oid "{1}" no longer exists in \
	the data store.  This may mean that you deleted the instance in a separate
\
	transaction, but this context still has a cached version.

The exception occurs at the line we call em.refresh() and seems to occur,
because the address object currently managed by the EntityManager does no
longer exist in the database. However, I would have assumed 'refresh'()
simply corrects the entities and removes the no-longer-existing object from
the database. Why does it throw an exception and what am I supposed to
change resp. do? How can I simply refresh the base object and all its
related relationships to make sure they reflect the correct state of the
tables?

If you need further information do not hesitate and ask. I hope I could
explain the problem.

Best regards,

Heiko
-- 
View this message in context: http://n2.nabble.com/EntityNotFoundException-caused-by-EntityManager-refresh-tp4901557p4901557.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: EntityNotFoundException caused by EntityManager.refresh()

Posted by Michael Dick <mi...@gmail.com>.

Heiko Kopp wrote:
> 
> Hello Mike,
> 
> first let me thank you for your help in this issue. It is really
> appreciated that for OpenJPA there is a great chance to get assistance in
> these kind of situations.
> 
Glad I could help. 

<snip> 


Heiko Kopp wrote:
> 
> This will work perfectly for me. I just need to make sure that in any case
> I call refresh and the external modification of the database might have
> happened, I make sure that the entity not found exception is caught. It is
> good to know, that a subsequent refresh() will not try to refresh the
> missing record. 
> 
> Interesting for me is, that although the exception is thrown, in case of
> refreshing on the Person and assuming that there is not only one
> CascadeType.REFRESH-typed OneToMany-relationship is present in person. How
> the heck (aeh hell) shall I find out WHERE the entity is no longer found
> ;-) It's not important for me right now, but really informative is
> something else .... 
> 
> For now, thank you very much again.
> 
> Greets,
> 
> Heiko
> 

The missing rows are stored in the nested exception, but you have to catch
an OpenJPA specific exception to get them, ie.

        try {
            em.refresh(p);
        } catch (org.apache.openjpa.persistence.EntityNotFoundException
enfe) {

            for(Throwable t : enfe.getNestedThrowables()) { 
                System.out.println(t);
            }

The toString on the exception will look something like this : 

<openjpa-1.3.0-SNAPSHOT-r422266:931580 nonfatal store error>
org.apache.openjpa.persistence.EntityNotFoundException: The following
instances do not exist in the data store: [3
[org.apache.openjpa.util.IntId], 2 [org.apache.openjpa.util.IntId]]

That's not terribly helpful. You know the primary keys for the rows that
failed (3 and 2 in my testcase), but not the tables that they belong to. You
can get the nestedExceptions again to get to the individual rows, but still 

I've opened  https://issues.apache.org/jira/browse/OPENJPA-1633 JIRA 1633 
to make this friendlier. 

I haven't looked into it in depth but we should be able to provide the table
or entity names in the exception. 

-mike
-- 
View this message in context: http://n2.nabble.com/EntityNotFoundException-caused-by-EntityManager-refresh-tp4901557p4914951.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: EntityNotFoundException caused by EntityManager.refresh()

Posted by Heiko Kopp <it...@daimler.com>.
Hello Mike,

first let me thank you for your help in this issue. It is really appreciated
that for OpenJPA there is a great chance to get assistance in these kind of
situations.


Michael Dick wrote:
> 
> I wish I had a more elegant solution to offer you. Something like this
> will also work : 
>         p = em.find(Person.class, 1);
>         System.out.println(p);
>         
>         try {
>             em.refresh(p);
>         } catch (EntityNotFoundException enfe) {
>             // If a related entity (Address) has been deleted in the
> database an EntityNotFoundException
>             // will be thrown. 
>             // To recover try refreshing again (OpenJPA will not refresh
> the same missing row a second time).
>             em.refresh(p);
>             assertEquals(2, p.getAddresses().size());
>         }
> 
> Whether this is better than calling em.find() is a matter of opinion. 
> 
> Hope this helps, 
> -mike 
> 

This will work perfectly for me. I just need to make sure that in any case I
call refresh and the external modification of the database might have
happened, I make sure that the entity not found exception is caught. It is
good to know, that a subsequent refresh() will not try to refresh the
missing record. 

Interesting for me is, that although the exception is thrown, in case of
refreshing on the Person and assuming that there is not only one
CascadeType.REFRESH-typed OneToMany-relationship is present in person. How
the heck (aeh hell) shall I find out WHERE the entity is no longer found ;-)
It's not important for me right now, but really informative is something
else .... 

For now, thank you very much again.

Greets,

Heiko
-- 
View this message in context: http://n2.nabble.com/EntityNotFoundException-caused-by-EntityManager-refresh-tp4901557p4914750.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: EntityNotFoundException caused by EntityManager.refresh()

Posted by Michael Dick <mi...@gmail.com>.

Heiko Kopp wrote:
> 
> Hello Mike, 
> 
> thanks first for your fast answer on this.
> 
> 
> Michael Dick wrote:
>> 
>> Do you have CascadeType.REFRESH or CascadeType.ALL specified for
>> Addresses? If a related entity no longer exists in the database then an
>> EntityNotFoundException needs to be thrown (spec p. 75).
>> 
> 
> Yes this is true, I added CascacdeType.REFRESH to the OneToMany()
> Relationship for the addresses. To make sure that in case a Person is
> refreshed, the list of addresses is refreshed too. However, I was not
> aware that this might lead to an exception.
> 

With CascadeType.REFRESH we call refresh on the Person entity and its
Address entities, if any of those don't exist in the database we have to
throw an EntityNotFoundException (page 75 in the JPA 1.0 spec under the
EntityNotFoundException paragraph). 

In this case it's correct behavior, but I can see how you might not have
expected it.



Heiko Kopp wrote:
> 
> 
> Michael Dick wrote:
>> 
>> It gets a little nebulous when you're talking about toMany relationships.
>> EntityManager.refresh() indicates that the contents of the entity are
>> updated from the database, but it looks like OpenJPA is refreshing the
>> entity, and any related entities based on the references in memory. I'd
>> say this is a bug, if you could open a 
>> https://issues.apache.org/jira/browse/OPENJPA JIRA issue  we'll start
>> working on the problem. Or if you don't have / don't want a JIRA account
>> I can open it on your behalf. 
>> 
> To understand you correctly: The spec says that if a related entity no
> longer exists in the database and the cascadeing type is set to REFRESH or
> higher, an exception must be thrown. In this case, the system works
> perfectly as it is and there is no bug. I was simply not aware that in
> this situation a EntityNotFoundException might be thrown.
> 
> However, if there should be no exception in case of CascadeType.REFRESH
> set on the OneToMany relationship to the addresses and the refresh is
> called uppon the Person, I should open a JIRA issue.
> 

Sorry for the confusion. To put it more clearly if you're cascading this is
a possible exception. If you aren't cascading then there's a different
problem. I'll open a JIRA for the other problem if you aren't worried about
it. 


Heiko Kopp wrote:
> 
> 
> Michael Dick wrote:
>> 
>> Your workaround seems safe for the time being. 
>> 
> Good, I will work with this for now. Let me add a question here. What is
> from your pespective the correct way of making sure that every external
> change of the database is reflected by the entity 'structure'? My thinking
> here was to use refresh() and add the CascadeType REFRESH to all
> relationships in the refreshed object. Now this might lead to the given
> EntityNotFoundException. Fine, but how to handle this? As you said
> yourself, my workaround is safe, but is it a good way of doing this?
> 
> Thank you for your help,
> 
> Heiko
> 

I wish I had a more elegant solution to offer you. Something like this will
also work : 
        p = em.find(Person.class, 1);
        System.out.println(p);
        
        try {
            em.refresh(p);
        } catch (EntityNotFoundException enfe) {
            // If a related entity (Address) has been deleted in the
database an EntityNotFoundException
            // will be thrown. 
            // To recover try refreshing again (OpenJPA will not refresh the
same missing row a second time).
            em.refresh(p);
            assertEquals(2, p.getAddresses().size());
        }

Whether this is better than calling em.find() is a matter of opinion. 

Hope this helps, 
-mike 
-- 
View this message in context: http://n2.nabble.com/EntityNotFoundException-caused-by-EntityManager-refresh-tp4901557p4913480.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: EntityNotFoundException caused by EntityManager.refresh()

Posted by Heiko Kopp <it...@daimler.com>.
Hello Mike, 

thanks first for your fast answer on this.


Michael Dick wrote:
> 
> Do you have CascadeType.REFRESH or CascadeType.ALL specified for
> Addresses? If a related entity no longer exists in the database then an
> EntityNotFoundException needs to be thrown (spec p. 75).
> 

Yes this is true, I added CascacdeType.REFRESH to the OneToMany()
Relationship for the addresses. To make sure that in case a Person is
refreshed, the list of addresses is refreshed too. However, I was not aware
that this might lead to an exception.


Michael Dick wrote:
> 
> It gets a little nebulous when you're talking about toMany relationships.
> EntityManager.refresh() indicates that the contents of the entity are
> updated from the database, but it looks like OpenJPA is refreshing the
> entity, and any related entities based on the references in memory. I'd
> say this is a bug, if you could open a 
> https://issues.apache.org/jira/browse/OPENJPA JIRA issue  we'll start
> working on the problem. Or if you don't have / don't want a JIRA account I
> can open it on your behalf. 
> 
To understand you correctly: The spec says that if a related entity no
longer exists in the database and the cascadeing type is set to REFRESH or
higher, an exception must be thrown. In this case, the system works
perfectly as it is and there is no bug. I was simply not aware that in this
situation a EntityNotFoundException might be thrown.

However, if there should be no exception in case of CascadeType.REFRESH set
on the OneToMany relationship to the addresses and the refresh is called
uppon the Person, I should open a JIRA issue.


Michael Dick wrote:
> 
> Your workaround seems safe for the time being. 
> 
Good, I will work with this for now. Let me add a question here. What is
from your pespective the correct way of making sure that every external
change of the database is reflected by the entity 'structure'? My thinking
here was to use refresh() and add the CascadeType REFRESH to all
relationships in the refreshed object. Now this might lead to the given
EntityNotFoundException. Fine, but how to handle this? As you said yourself,
my workaround is safe, but is it a good way of doing this?

Thank you for your help,

Heiko



-- 
View this message in context: http://n2.nabble.com/EntityNotFoundException-caused-by-EntityManager-refresh-tp4901557p4911510.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: EntityNotFoundException caused by EntityManager.refresh()

Posted by Michael Dick <mi...@gmail.com>.
Hi Heiko, 

Do you have CascadeType.REFRESH or CascadeType.ALL specified for Addresses?
If a related entity no longer exists in the database then an
EntityNotFoundException needs to be thrown (spec p. 75).

It gets a little nebulous when you're talking about toMany relationships.
EntityManager.refresh() indicates that the contents of the entity are
updated from the database, but it looks like OpenJPA is refreshing the
entity, and any related entities based on the references in memory. I'd say
this is a bug, if you could open a 
https://issues.apache.org/jira/browse/OPENJPA JIRA issue  we'll start
working on the problem. Or if you don't have / don't want a JIRA account I
can open it on your behalf. 

Your workaround seems safe for the time being. 

Thanks for reporting this, 
-mike 


-- 
View this message in context: http://n2.nabble.com/EntityNotFoundException-caused-by-EntityManager-refresh-tp4901557p4910126.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: EntityNotFoundException caused by EntityManager.refresh()

Posted by Heiko Kopp <it...@daimler.com>.
Hello Mike,


Michael Dick wrote:
> 
> Hi Heiko,
> 
> Could the entity, or any of the entities it's related to, have been
> deleted from the database? 
> 
> You're using a fairly old snapshot version of 1.3.0 and there have been a
> lot of changes. Can you try with an updated snapshot? You can grab the
> latest snapshot from
> http://people.apache.org/repo/m2-snapshot-repository/org/apache/openjpa/apache-openjpa/1.3.0-SNAPSHOT/. 
> 
> Regards
> -mike
> 

I've now tried the newest version of OpenJPA 1.3, but still the error
occurs. If an address is deleted and a refresh is done to the person object
itself, thus the situation is as follows:

find(id) leads to

Person (entity)
    List of Addresses
         Address A (entity)
         Address B (entity)
         Address C (entity)

Now, outside of the scope of the application lets assume the table entry of
'Address B' is deleted from the database.

A second find(id) should (from my perspective) lead to 

Person (entity)
    List of Addresses
         Address A (entity)
         Address C (entity)

but throws the EntityNotFoundException at 'refresh()' for the Entity of
Address B.

My current solution to this is, that in case the exception occurs, I simply
repeat what I did, thus call find() and refresh() once again. This works
now, but I'm really unsure if its a good solution this way.

Any ideas?

Best regards,

Heiko
-- 
View this message in context: http://n2.nabble.com/EntityNotFoundException-caused-by-EntityManager-refresh-tp4901557p4906091.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: EntityNotFoundException caused by EntityManager.refresh()

Posted by Heiko Kopp <it...@daimler.com>.
Hello Mike,

that is true, one entity in the OneToMany relationship (one of the
addresses) has been deleted in the database. 

Thus the situation would be as follows:

first find of a person leads to:

Person
   - List of Addresses
          Address A
          Address B

Now Address B is deleted from the database by an external, non-controllable
application.

If I now do a find on Person and a subsequent call to refresh() on the
person object, the Person still exists, and the entity of Address B in the
list of addresses exists too (being in an undefined state, halfway
detached?), but no longer in the database. I think thats what leads to the
EntityNotFoundException. Interestingly, this is not always the case, just
sometimes the situation occurs. 

I will asap try the newest snapshot of 1.3 and try this one. Maybe things
have fixed already.

Thank you for your help. Unfortunately I'm not able to switch to OpenJPA 2.0
cause WebSphere 6.1 does not work with it :-(

What is in general the correct way of handling an EntityNotFoundException?
Should the base entity (Person) be detached? 

I was thinking of trying to use a NamedQuery that does a SELECT p from
Person p WHERE p.id = ... instead of doing a find(), though unsure if that
is in any way different to a find.

Any further ideas are appreciated. I will be back with news of the newest
snapshot of 1.3.

Best regards,

Heiko
-- 
View this message in context: http://n2.nabble.com/EntityNotFoundException-caused-by-EntityManager-refresh-tp4901557p4903008.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: EntityNotFoundException caused by EntityManager.refresh()

Posted by Michael Dick <mi...@gmail.com>.
Hi Heiko,

Could the entity, or any of the entities it's related to, have been deleted
from the database? 

You're using a fairly old snapshot version of 1.3.0 and there have been a
lot of changes. Can you try with an updated snapshot? You can grab the
latest snapshot from
http://people.apache.org/repo/m2-snapshot-repository/org/apache/openjpa/apache-openjpa/1.3.0-SNAPSHOT/. 

Regards
-mike
-- 
View this message in context: http://n2.nabble.com/EntityNotFoundException-caused-by-EntityManager-refresh-tp4901557p4902588.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.