JR Galia
JR Galia

Reputation: 17269

Access Parent Entity in JPA Entity

Im using JPA 1, Struts2.3.1, Google-App-Enging 1.7.0

In my Comics I have property below with getter and setter:

@ManyToOne(fetch=FetchType.LAZY, targetEntity=User.class)
private User user = null;

My method for JPA query:

public Comics readComics(int random, String url){
    EntityManager em = EMF.get().createEntityManager();
    Comics comics = null;

    try{
        Query q = em.createNamedQuery("Comics.getComics");
        q.setParameter("random", random);
        q.setParameter("url", url);
        comics = (Comics) q.getSingleResult();

    } catch(NoResultException ex){
        System.out.println("ERROR CATCHED: " + ex.getMessage());
        comics = null;
    } finally{
        em.close();
    }

    return comics;
}

In my view, I have:

<s:property value="comics.user.userName"/>

userName can't be accessed in that case, but when entity manager is not closed userName is displayed.

What would be the correct one? Is it okay to remove em.close()?

=======================

Using BeanUtils.copyProperties I also tried code below:

Comics emComics = (Comics) q.getSingleResult();
BeanUtils.copyProperties(comics, emComics);
BeanUtils.copyProperties(comics.getUser(), emComics.getUser());

Is it the correct way of using copyProperties? Removing BeanUtils.copyProperties(comics.getUser(), emComics.getUser()); will again not display the user

Upvotes: 2

Views: 325

Answers (1)

gkamal
gkamal

Reputation: 21000

It is not ok to remove em.close() - if you do that you will end up with connection leaks. The application will stop working after all the connections in the pool are exhausted.

Simple fix is the make sure everything needed by the jsp in initialized before calling em.close().

If you are using hibernate as the provider then you can use Hibernate.initialize()

public Comics readComics(int random, String url){
    EntityManager em = EMF.get().createEntityManager();
    Comics comics = null;
   try{
        Query q = em.createNamedQuery("Comics.getComics");
        q.setParameter("random", random);
        q.setParameter("url", url);
        comics = (Comics) q.getSingleResult();

        Hibernate.initialize(comics.getUser());

    } catch(NoResultException ex){
        System.out.println("ERROR CATCHED: " + ex.getMessage());
        comics = null;
    } finally{
        em.close();
    }

    return comics;
}

If you are using some other provider you can look for an equivalent method or just write own function that just fetches one of the properties of the object to trigger the initialization of the proxy.

Another option is to modify the query using a join fetch to fetch the User association while fetching the comics.

The correct solution to this is to use either Spring or EJBs that provide solutions to easily deal with entity manager. Your approach of opening a new entityManager for each query is not optimal - it should ideally be one entityManager per transaction or for the whole request. Read up about lazy initialization exception, OpenSessionInViewFilter etc..

Upvotes: 2

Related Questions