Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How solve javax.persistence.EntityNotFoundException with JPA (not by using @NotFound)

We are using JPA to load some stuff from a database. Some entities may have optional relationships between them, e.g.

@Entity
public class First {
    ....
    @OneToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
    @JoinColumns(value = {
        JoinColumn(name = "A_ID", referencedColumnName = "A_ID", insertable = false, updatable = false), 
        JoinColumn(name = "B_ID", referencedColumnName = "B_ID", insertable = false, updatable = false)})
    private Second second;

When this association is present in the database, everything is working fine. When it's not, I'm getting a javax.persistence.EntityNotFoundException
What I want is instead of the exception to have this field as NULL if the association is not present.

I have tried several different things, e.g. using the optional=true in the relationship annotation (which btw is the default option), putting it as Nullable, etc. Nothing seems to do the trick, it seems like all these options are being ignored.

I found a lot of links mentioning this very same problem (and some questions here in stackoverflow) but in all of them the suggestion is to use the @NotFound annotation from Hibernate. But we do NOT want to have any dependencies to Hibernate (we want to keep everything pure JPA).

Does any of you guys know any other way to solve this?

Many thanks for all your help!

like image 277
Alex Ntousias Avatar asked Sep 04 '12 10:09

Alex Ntousias


People also ask

How do I fix EntityNotFoundException?

Combining @NotFound(action = NotFoundAction. IGNORE) with @ManyToOne annotation will stop the persistence provider from throwing the EntityNotFoundException, but we'll have to handle missing entity by hand to avoid NullPointerException.

What is the easiest way to ignore a JPA field during persistence?

use @Transient to make JPA ignoring the field.

How do you handle javax persistence NoResultException No entity found for query?

You need to use the try/catch block, but no need to catch the Exception . As per the API it will throw NoResultException if there is no result, and its up to you how you want to handle it. DrawUnusedBalance drawUnusedBalance = null; try{ drawUnusedBalance = (DrawUnusedBalance)query.

How does spring boot handle EntityNotFoundException?

Create a method called handleEntityNotFound() and annotate it with @ExceptionHandler , passing the class object EntityNotFoundException. class to it. This declaration signalizes Spring that every time EntityNotFoundException is thrown, Spring should call this method to handle it.


3 Answers

Below is an alternative solution for this problem. I had to build on top of an old database where the relations sometimes were corrupt. This is how I solved it by only using JPA.

@PostLoad
public void postLoad(){
    try {
        if(getObject() != null && getObject().getId() == 0){
            setObject(null);
        }
    }
    catch (EntityNotFoundException e){
        setObject(null);
    }
} 
like image 88
Björn Avatar answered Oct 11 '22 20:10

Björn


I've met the same problem. It's not always reproducable, so I cannot test it, but here are some thoughts:

  1. The instance of your Second class is deleted, while the instance of the First class does not know anything about that.
  2. You need a way to let an instance of First know, when its instance of Second is deleted.
  3. cascade option for removing does not help here.
  4. You may try to use bidirectional relationship, when instance of First exists inside instance of Second. It let you update instance of First via instance of Second before removing second
  5. Bidirectional relationship - is evil. I would suppose in your case, that First - is owner of Second. Don't allow any service delete your Second instance directly. Let service which works with instances of First remove instance of Second. In this case you may make the "second" field nullable first, than remove instance of Second via EntityManager.
  6. You may get exception when execute queries and the 2nd level cache is enabled and query has a hint, which allows to cache its result. I would offer you get result of queries via the following method:
private List<?> getQueryResult(final Query query)
{
    try
    {
        return query.getResultList();
    }
    catch (EntityNotFoundException e)
    {
        return query.setHint("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH).getResultList();
    }
}
  1. If you work with entities via EntityManger, but not via queries, and you get exception because entity is cached, you may invalidate all entities of First in cache when you delete Second.

I'd like to discuss this solution, as I cannot test it and cannot make sute it works. If somebody tries, please let me know.

PS: if somebody has a unit test for hibernate, that reproduces this issue, could you please let me know. I wish to investigate it further.

like image 23
Alexandr Avatar answered Oct 11 '22 21:10

Alexandr


It happens when you delete the associated entity id. In my case I had Product table depending upon Brand table. I deleted a row or an entity of brand id to which one of the product instance was depending upon.

like image 45
Dila Gurung Avatar answered Oct 11 '22 20:10

Dila Gurung