簡體   English   中英

在 Spring JSP 頁面中使用集合時 Hibernate LazyInitializationException

[英]Hibernate LazyInitializationException while using collection in Spring JSP page

我有這樣的實體:

@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<AssessmentPart> assessmentParts = new LinkedList<>();

    public List<AssessmentPart> 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
}

評估部分是從評估實體延遲加載的。 我還有 spring 控制器方法,它是事務性的,並從數據庫中加載評估部分:

@Transactional
public void doSomething(String partId, Map<String, Object> 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 來循環它們:

<c:forEach var="assessmentPart" items="${assessmentParts}">
     //Not loading any lazy stuff, just getting an ID of assessment part
</c:forEach>

從這個 JSP 頁面拋出異常:

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<String, Object> 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());

初始化您的收藏。

方法調用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 將加載 Assessment @ManyToOne(fetch = FetchType.EAGER)

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

嘗試從評估中提取 AssessmentParts 將不起作用,因為它不是@OneToMany(fetch = FetchType.LAZY)並且會話已經關閉

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

使用新方法從 EntityManager 中通過 Assessment 獲取 AssessmentParts 列表應該可以解決問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM