9

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.

Community
  • 1
  • 1
raksja
  • 3,781
  • 3
  • 34
  • 44
  • What was wrong with the optional=true? could you print out the query Hibernate generates if you have that set? I've used optional=true on OneToMany relationships before just fine. Another possibility you might want to try is using JoinColumn, and nullable = true – Jeff Wang Sep 17 '14 at 16:45
  • optional=true didnt do anything, no errors. will look for the code base and try to get the query. – raksja Sep 22 '14 at 16:20
  • could you post your persistence.xml? (at least the part needed for your presented domain)... Moreover: What version of JPA are you using or "bound" to use? – MWiesner Mar 27 '15 at 16:48
  • Add an attribute inverse = "false" . it will make relation unidirectional and will never try to fetch record from UserDetail table. – Zealous System Apr 09 '15 at 10:23
  • Do you load that object with Session.load or with a JPQL query ? Some annotations or parameters only work when loading an object via its ID. – Olivier Croisier Apr 14 '15 at 13:09

1 Answers1

3

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.

Community
  • 1
  • 1
DuncanKinnear
  • 4,241
  • 2
  • 31
  • 62