Search code examples
hibernatespring-mvcejbjpa-2.0lazy-initialization

Join fetch in JPA sometimes causes LazyInitializationException


I am having this issue with JPA in my application. I have a parent entity Artist with one-to-one/many etch relations to other entities which I have all set to be lazily fetched. I fetch these entities using join queries. This all seems to work fine but sometimes i get a LazyInitializationException. I am using Stateless EJB's with JPA in the backend and Spring MVC in the web layer. Here is the method:

public Artist getArtistWithChildren(long id, boolean isFetchReviews, boolean isFetchRequests, boolean isFetchGigs, boolean isFetchVenues) {
    StringBuilder sql = new StringBuilder();
    sql.append("select a from Artist a join fetch a.members mrs");
    if(isFetchReviews) {
        sql.append(" left join a.reviews rvs");
    } if(isFetchRequests) {
        sql.append(" left join a.requests rqs");
    } if(isFetchGigs) {
        sql.append(" left join a.gigs gs");
    } if(isFetchVenues) {
        sql.append(" left join a.venues vs");
    }

    sql.append(" where a.id=:id");

    TypedQuery<Artist> query = em.createQuery(sql.toString(), Artist.class);
    query.setParameter("id", id);
    query.setMaxResults(1);
    List<Artist> resultList = query.getResultList();
    return resultList.get(0);
}

And here is the entity class Artist

@Entity
@Table(name="ARTIST")
public class Artist extends DescribingEntity {

private static final long serialVersionUID = -7264327449601568983L;

@ManyToMany(mappedBy="artists", targetEntity=Member.class, fetch=FetchType.LAZY, cascade={MERGE, REFRESH})
private List<Member> members;

@OneToMany(mappedBy="artist", targetEntity=VenueReview.class, fetch=FetchType.LAZY, cascade={MERGE, REFRESH, REMOVE})
private List<VenueReview> reviews;

@OneToMany(mappedBy="artist", targetEntity=Gig.class, fetch=FetchType.LAZY, cascade={MERGE, REFRESH, REMOVE})
private List<Gig> gigs;

@OneToMany(mappedBy="artist", targetEntity=GigRequest.class, fetch=FetchType.LAZY, cascade={MERGE, REFRESH, REMOVE})
private List<GigRequest> requests;

@ManyToMany(cascade={MERGE, REFRESH}, fetch=FetchType.LAZY)
@JoinTable(name="VENUE_ARTIST_REL", 
    joinColumns=@JoinColumn(name="ARTIST_ID", referencedColumnName="ARTIST_ID"), 
    inverseJoinColumns=@JoinColumn(name="VENUE_ID", referencedColumnName="VENUE_ID"))
private List<Venue> venues;

getters and setters...

I then go into debug mode to find out what went wrong and as I am stepping through the method it returns no error and no exception is thrown. Could it be that the collection is returned too soon so that all data from the DB has not had the time to populate correctly? I am a newbie when it comes to JPA so please let me know what I did wrong. Here is an example. I am using left joins here since I dont HAVE to get the results, but I doo need an instantiated collection.

I have tested the same thing using Arquillian and no errors, I also have similar methods for other entities where the scenario is the same, simply running it causes the error while step-through debugging don't.

Using Hibernate.initialize(Object o) on the child collections works fine but to my knowledge it is not a good thing to do since I then have to make a DB query for each child (correct me if I'm wrong).

I added a pastebin link to the stack trace

Stack Trace


Solution

  • In General, LazyInitializationException happens when you're lazy loading on a collection and trying to access that collection with out having a Session that encloses the context (method essentially) in which you're trying to access the lazy collection. It would be much more helpful, if you can post your error stack trace to get an exact resolution to your problem