在Spring JSP页面中使用集合时的Hibernate LazyInitializationException

我有这样的实体:

@Entity @Table(name = "ASSESSMENT") public class Assessment { //All other fields.. @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "assessment") @OrderBy(value = "order ASC") private List assessmentParts = new LinkedList(); public List getAssessmentParts() { return assessmentParts; } //All other getters/setters } 

另一个:

 @Entity @Table(name = "ASSESSMENT_PART") public class AssessmentPart { //All other fields @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "ASSESSMENT_ID", nullable = false) private Assessment assessment; public Assessment getAssessment() { return assessment; } public void setAssessment(Assessment assessment) { this.assessment = assessment; } //All other getters/setters } 

评估部分从评估实体延迟加载。 我也有弹簧控制器方法,它是Transactional并从数据库中加载评估部分:

 @Transactional public void doSomething(String partId, Map model) { AssessmentPart assessmentPart = //laods a part with entity manager Assessment assessment = assessmentPart.getAssessment(); //Getting the assessments model.put("assessmentParts", assessment.getAssessmentParts()); //adding all assessments parts into spring model map } 

一旦我将评估部分添加到spring模型映射中,它们就可以在我的JSP页面中使用,我使用JSTL循环遍历它们:

  //Not loading any lazy stuff, just getting an ID of assessment part  

从此JSP页面抛出exception:

 org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: my.package.something.Assessment.assessmentParts, could not initialize proxy - no Session 

如果此集合已在事务中加载,这怎么可能? 我只是试图循环,hibernate此时不应该加载任何东西,因为它已经加载了。 为什么会发生这种奇怪的事情?

在视图中,entitymanager已经关闭,因此集合中的元素无法检索其属性。 您在控制器中编写的代码不会初始化集合中的元素(它是一个LAZY集合),但只初始化集合(而不是其中的元素)。

通过在Web配置中配置OpenEntityManagerInViewFilter ,强制实体管理器保持打开状态。

或者更改您的控制器代码以包含对Hibernate.initialize的调用以正确初始化您的集合。

 @Transactional public void doSomething(String partId, Map model) { AssessmentPart assessmentPart = //laods a part with entity manager Assessment assessment = assessmentPart.getAssessment(); //Getting the assessments Hibernate.initialize(assesment.getAssesmentParts()); // Init collection model.put("assessmentParts", assessment.getAssessmentParts()); //adding all assessments parts into spring model map } 

要么是这样,要么创建一个强制急切提取集合的自定义查询。

更改

 model.put("assessmentParts", assessment.getAssessmentParts()); 

 Hibernate.initialize(assessment.getAssessmentParts()); 

初始化您的collections。

方法调用assessment.getAssessmentParts()未初始化您的集合。 这个方法调用只会返回一个集合包装器,你需要将这个包装器传递给Hibernate.initialize方法进行手动初始化。

编辑:

使用JPA,您可以使用JPQL Fetch Joins获取AssessmentParts以及Assessment (在任何需要的地方),覆盖默认行为:

 SELECT a FROM Assessment asmt LEFT JOIN FETCH asmt.assessmentParts WHERE asmt.id = :id 

从EntityManager加载AssessmentPart将加载评估@ManyToOne(fetch = FetchType.EAGER)

 AssessmentPart assessmentPart = //laods a part with entity manager Assessment assessment = assessmentPart.getAssessment(); 

试图从评估中提取AssessmentPart不会起作用,因为它不是@OneToMany(fetch = FetchType.LAZY)并且会话已经关闭

 model.put("assessmentParts", assessment.getAssessmentParts()); 

从EntityManager获取AssessmentParts列表,以新方法解决问题。