Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OneToOne + No Foreginkey + Unidirectional + Datamissing => EntityNotFoundException

From a legacy system, we have 1 table (Entity) and 1 view (UserDetail) with no constraints but with relations.

Entity
| Id | Desc | Created_By |...

UserDetail
| UserId | F_Name | L_Name |...

CreatedBy has the userid of the user who created that entity. We have a unidirectional mapping in Entity.java like below.

@OneToOne
@JoinColumn(name = "CREATED_BY", referencedColumnName = "USER_ID")
private UserDetail createdBy;

Problem

But since its a legacy system, we don't have control on that and an user is hard deleted.

When the entityReposity.findAll is called, following error is thrown

org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to find com...UserDetail with id 92237; nested exception is javax.persistence.EntityNotFoundException: Unable to find com...UserDetail with id 92237

Question

How to make the JPA consider this association is optional or is there any way in JPA to make it ignore (like @NotFound in Hibernate)?

Tried

  1. @NotFound works, but we need to hack @OneToOne as @ManyToOne. Also we want an implementation independent solution. Noticed this bug too, https://hibernate.atlassian.net/browse/ANN-725

  2. optional=true - If this would have worked as per the syntactical meaning on how it should behave, I wouldn't have written this.

  3. Also tried the postLoad() in UserDetails.java.

  4. @PostLoad solution We have aop exceptionhandler and exception is caught there before @PostLoad in Entity class gets called.

In Entity.java

    @PostLoad
    public void postLoad(){
        try {
            System.out.println(this.getCreatedBy()); //Before control comes here, it goes to aop exception handler
        }
        catch (EntityNotFoundException e){
            setCreatedBy(null);   
        }
    }

Any help would be appreciated.

like image 452
raksja Avatar asked Aug 22 '14 00:08

raksja


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.

When to use EntityNotFoundException?

Class EntityNotFoundException Thrown when EntityManager. refresh is called and the object no longer exists in the database. Thrown when EntityManager. lock is used with pessimistic locking is used and the entity no longer exists in the database.


1 Answers

As crazy as it sounds, you need to make the @OneToOne association optional = false. See this question and answer for an explanation.

So the code for the association would be:

@OneToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "CREATED_BY", referencedColumnName = "USER_ID")
private UserDetail createdBy;

Of course the trouble is that if you try to access the associated createdBy association, then Hibernate will try to lazy-load the associated Entity and you will get the same exception.

The @NotFound is really your best bet.

like image 72
DuncanKinnear Avatar answered Sep 19 '22 12:09

DuncanKinnear