我使用 JPA 1、Struts2.3.1、Google-App-Enging 1.7.0
在我的漫画中,我有以下带有 getter 和 setter 的属性:
@ManyToOne(fetch=FetchType.LAZY, targetEntity=User.class)
private User user = null;
我的JPA查询方法:
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;
}
在我看来,我有:
<s:property value="comics.user.userName"/>
userName
在这种情况下无法访问,但是当实体管理器未关闭时 userName
显示。
正确的是什么?可以删除em.close()
吗? ?
========================
使用 BeanUtils.copyProperties
我还尝试了下面的代码:
Comics emComics = (Comics) q.getSingleResult();
BeanUtils.copyProperties(comics, emComics);
BeanUtils.copyProperties(comics.getUser(), emComics.getUser());
copyProperties
的正确使用方法是吗? ?正在删除BeanUtils.copyProperties(comics.getUser(), emComics.getUser());
将再次不显示user
最佳答案
删除 em.close() 是不行的 - 如果这样做,最终会导致连接泄漏。当池中的所有连接耗尽后,应用程序将停止工作。
简单的修复是确保在调用 em.close() 之前初始化 jsp 所需的所有内容。
如果您使用 hibernate 作为提供程序,那么您可以使用 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;
}
如果您正在使用其他提供程序,您可以寻找等效的方法,或者只编写自己的函数,该函数仅获取对象的属性之一以触发代理的初始化。
另一个选项是使用连接获取来修改查询,以在获取漫画时获取用户关联。
正确的解决方案是使用 Spring 或 EJB,它们提供了轻松处理实体管理器的解决方案。为每个查询打开一个新的实体管理器的方法并不是最佳的 - 理想情况下,每个事务或整个请求应该有一个实体管理器。阅读有关延迟初始化异常、OpenSessionInViewFilter 等的信息。
关于java - 访问 JPA 实体中的父实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12361609/