由于没有会话而未能懒惰地初始化集合

时间:2014-02-21 20:49:27

标签: java spring hibernate

在使用hibernate的spring mvc应用程序中,我收到以下错误消息:

root cause  
org.hibernate.LazyInitializationException:  
failed to lazily initialize a collection of role:  
org.springframework.samples.knowledgemanager.model.Encounter.providers,  
could not initialize proxy - no Session

当我尝试访问另一个arraylist中每个对象的属性arraylist时,抛出错误。具体来说,我有一个名为Encounter的{​​{1}}个对象的arraylist,每个encountersforday个对象都有一个属性提供者,它是Encounter个对象的arraylist。当我尝试使用spring表达式语言从jsp调用Provider arraylist时抛出错误,如下所示:

providers

上面的代码引用了以下控制器代码:

<spring:eval expression="encountersforday.get(2).getProviders()" var="myps" />
<c:forEach var="id" items="${myps}" varStatus="k">//this is the line throwing error
    <spring:eval expression="id==3" var="match_id"></spring:eval>
    <c:choose>
        <c:when test="${match_id==true}">true</c:when>
        <c:otherwise>false</c:otherwise>
    </c:choose>
</c:forEach>

//获取日历中列的提供者列表
        列表ps =(列表)clinicService.findProvidersByFacilityAddressId(7);         model.addAttribute(“ps”,ps);         for(int g = 0; g

@RequestMapping("/calendar")
public String showCalendar(@RequestParam("day") String day, org.springframework.web.context.request.WebRequest webRequest, Model model) {
    String pid = webRequest.getParameter("pid");
    System.out.println("............ pid is:  "+pid);
    model.addAttribute("pid", pid);
    LocalDate mydate;
    if(day.equals("")){mydate = new LocalDate();}
    else{mydate = new LocalDate(day);}
    System.out.println("------------------------ in controller, day of month is:  "+mydate.getDayOfMonth());
    AppointmentCalendar calendar = new AppointmentCalendar(mydate); // Or whatever you do to create it
    List<Encounter> encountersforday = (List<Encounter>) clinicService.getEncountersForDay(mydate);
    model.addAttribute("calendar", calendar);
    model.addAttribute("encountersforday", encountersforday);
    System.out.println("number of encountersforday is: "+encountersforday.size());
    List<LocalTime> myblocks = calendar.getBlocks();
    int[][] filledblocks = new int[myblocks.size()][3];
    for(Integer i=0;i<encountersforday.size();i++){
        System.out.println("i, encounterid, patientid, first, last, dateTime are: "+i+", "+encountersforday.get(i).getId()+", "
    +encountersforday.get(i).getPatient().getId()+", "+encountersforday.get(i).getPatient().getFirstName()+", "+encountersforday.get(i).getPatient().getLastName()+", "+encountersforday.get(i).getDateTime());
        for(Integer g=0;g<myblocks.size();g++){
            filledblocks[g][0] = g;//blockid
            if(myblocks.get(g).getHourOfDay()==encountersforday.get(i).getDateTime().getHourOfDay()){
                if(myblocks.get(g).getMinuteOfHour()==encountersforday.get(i).getDateTime().getMinuteOfHour()){
                    int hours = myblocks.get(g).getHourOfDay();
                    int mins = myblocks.get(g).getMinuteOfHour();
                    System.out.println("found match at: "+hours+":"+mins);
                    filledblocks[g][1] = i+1;//encounterid
                    filledblocks[g][2] = 1;//segmentindex
                }
            }
        }
    }

    for(int k=0;k<filledblocks.length;k++){
        System.out.println("blockid, encounterid, segmentnum are: "+filledblocks[k][0]+", "+filledblocks[k][1]+", "+filledblocks[k][2]);
    }
    model.addAttribute("filledblocks", filledblocks);

点击以下链接可以在文件共享网站上找到实际实体的代码

可以找到 return "appointments/calendar"; } 实体的代码at this link 可以找到Encounter实体的代码at this link

这是完整的堆栈跟踪:

Provider

1 个答案:

答案 0 :(得分:4)

不知何故(它在您发布的代码中不可见,并且不是非常重要)您的clientService正在使用Session对象来获取Encounter个对象的列表。该Session对象具有close方法,该方法在Session完成时调用。调用close方法后,除非已初始化,否则无法访问延迟初始化的属性。

这让大多数人感到高兴,因为大多数人实际上并没有自己打开和关闭Hibernate会话,而是由底层框架处理。例如,如果您使用的是Spring,则可能会使用@Transactional@PersistenceContext注释,这些注释是开启和关闭会话(在这种情况下,会话在事务结束时关闭,例如你离开@Transactional方法的范围。

最终,无论你做什么,可用的解决方案都是一样的。最简单的解决方案是简单地将Encounter的提供者关系标记为渴望关系(例如@ManyToMany(... fetch=FetchType.EAGER ...)),但如果有很多地方加载Encounter对象而不是Provider对象,这可能会影响性能。

另一个“全局”解决方案是扩展您的事务范围,以便JSP的处理实际上在您的事务处理请求中。这通常通过将事务的开始和停止放在过滤器中来完成。虽然有时这对人们也不起作用。

一个非常有针对性的解决方案是在将每个对象传递给JSP层之前使用静态方法Hibernate.initialize()进行初始化:

List<Encounter> encountersforday = (List<Encounter>) clinicService.getEncountersForDay(mydate);
for(Encounter encounter: encountersforday) {
    Hibernate.initialize(encounter.getProviders());
}

也可能有其他解决方案,但这些都是想到的。我希望你能在这方面取得进展。