Reputation: 17269
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
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