failed to lazily initialize a collection of role

I get the following error in Openmrs 1.9.10:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: org.openmrs.Location.tags, no session or session was closed at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383) at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375) at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:368) at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:111) at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:186) at org.openmrs.module.chica.advice.QueryImmunizationForecast.run(QueryImmunizationForecast.java:78) at java.lang.Thread.run(Thread.java:745)

public class QueryImmunizationForecast implements ChirdlRunnable {

public void run() { Context.openSession();

    AdministrationService adminService = Context
        .getAdministrationService();
    Context.authenticate(adminService
            .getGlobalProperty("scheduler.username"), adminService
            .getGlobalProperty("scheduler.password"));
    ChirdlUtilBackportsService chirdlutilbackportsService = Context
        .getService(ChirdlUtilBackportsService.class);
    EncounterService encounterService = Context
        .getService(org.openmrs.module.chica.service.EncounterService.class);
    
    try {

        
        //encounter/session
        Integer encounterId = encounter.getEncounterId();
        List<Session> sessions = chirdlutilbackportsService.getSessionsByEncounter(encounterId);
        Session session = sessions.get(0);
        Integer sessionId = session.getSessionId();
        
        //location
        Integer locationTagId = null;
        Integer locationId = null;
        org.openmrs.module.chica.hibernateBeans.Encounter chicaEncounter 
                = (org.openmrs.module.chica.hibernateBeans.Encounter) encounterService
                .getEncounter(encounter.getEncounterId());
        String printerLocation = chicaEncounter.getPrinterLocation();
        if (printerLocation != null)
        {
            Location location = encounter.getLocation();
            Set<LocationTag> tags = location.getTags();
            for(LocationTag tag:tags){ //error is here
                if(printerLocation.equalsIgnoreCase(tag.getTag())){
                    locationTagId = tag.getLocationTagId();
                    locationId = location.getLocationId();
                    break;
                }
            }
        }
        
        //patient state
        State queryImmunizationListState = chirdlutilbackportsService.getStateByName("Query Immunization Forecast");
        PatientState state = chirdlutilbackportsService.addPatientState(encounter.getPatient(), queryImmunizationListState, 
            sessionId, locationTagId, locationId, null);
    
        //send POST and create immunization list
        ImmunizationRegistryQuery.queryCHIRP(encounter);
                
        state.setEndTime(new java.util.Date());
        chirdlutilbackportsService.updatePatientState(state);
        

    } catch (Exception e) {
        log.error("Immunization Query exception: ", e);
        
    } finally {
        Context.closeSession();
    }
}

It seems like the Hibernate session used to retrieve the Encounter is closed and the location attribute is just a proxy. Are you opening a new session in this class ? Nesting sessions in general is not recommended.

This is a thread. As far as I know, I must open a session of some kind in a thread class. This code worked fine in Openmrs 1.7.x but breaks in 1.9.x some I’m not sure what changed with session management. It seems like the session gets closed as soon as the encounter is retrieved.

I don’t know of any specific changes that would have caused this to break, but these days we recommend against the scheduler.username/scheduler.password approach (since it exposes login credentials within the app), but instead you should use this method:

Daemon.runInDaemonThread(final Runnable runnable, DaemonToken token)

Apparently we have no wiki documentation about this, but the idea is that if your module activator defines a setDaemonToken(DaemonToken) method then it will be called on startup, and you can later use this token to execute code in a daemon thread (which is already authenticated, by the framework)

See usage in the idgen module at https://github.com/openmrs/openmrs-module-idgen/search?utf8=✓&q=daemontoken

Is this the code?

https://github.com/CHIRDL-Openmrs-Modules/chica/blob/master/src/org/openmrs/module/chica/advice/QueryImmunizationForecast.java

The encounter passed in the constructor was retrieved in another session and has attributes not loaded (location at least, but can be any), This is bad in general because you shouldn’t assume all the attributes are hydrated. Core services must not load eagerly all the attributes for performance reasons.

I suggest to pass the encounter id to the constructor and load the Encounter object in this session.

Another option (if changing the constructor is not feasible) is to reattach the Encounter to the current session. See http://stackoverflow.com/questions/912659/what-is-the-proper-way-to-re-attach-detached-objects-in-hibernate

@lluismf Thanks. That did the trick. @darius Thank you for the suggestion. It is a little tricky for us to do that since we use Thread pooling and don’t have an easy way to control how the thread is executed. Thank you both for your help.