Search code examples
javajpapersistencelazy-loadingopenjpa

After updating an entity that has Lazy Loaded attributes JOIN FETCH has no effect


We have an entities like this:

public User {
    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "user_id", insertable = true, updatable = true)
    @ElementDependent
    private List<Item_x> item_x_list = new ArrayList<Item_x>();
}

public Item_x {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", insertable = true, updatable = true)
    @Element(name = "user_id", required = false)
    private Users user;
}

Whenever I add/remove items to User.item_x_list and then persist the User entity using em.merge(User.INSTANCE) the Item_x.user property is NULL.

I am loading the Item_x.user property with a JOIN FETCH query to make sure the attribute is loaded (when I need it). However: the Item_x.user property is NULL even with FETCH JOIN if you have performed a merge on the User Entity.

I tried to workaround by refreshing the Item_x.INSTANCE but when I call:

em.refresh(Item_x.Instance);

=> user is null.

Looking in the database I of course can see that the user is NOT null in the Item_x.

How can I force OpenJPA to correctly load the user in Item_x ? Why is OpenJPA not filling correctly the Item_x.user property / ignores the JOIN FETCH statement?


Solution

  • It looks like the problem is that you've created two uni-directional relationships instead of a bi-directional relationship. One of your classes needs to define a mappedBy relation to the other class, which defines the other class as the "owner" of the relationship. For example, you can change your example above to define Item_x as the owner as follows:

    public User {
        @OneToMany(targetEntity = Item_x.class, mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
        @ElementDependent
        private List<Item_x> item_x_list = new ArrayList<Item_x>();
    }
    
    public Item_x {
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "user_id", insertable = true, updatable = true)
        @Element(name = "user_id", required = false)
        private Users user;
    }
    

    More information is available in the OpenJPA documentation, but they're missing examples which would make it more clear.