Exception thrown due to lazy initialization of a eagerly fetched (detached) collection

Let's start with some details:

  • My technology stack includes:
    • Spring 3.1.1.RELEASE
    • Hibernate 4.1.5.SP1
    • JSF 2.0?
    • OpenSessionInViewFilter (org.springframework.orm.hibernate4.support.OpenSessionInViewFilter)
    • PrimeFaces 3.3.1
    • Lombok 0.11.2
    • JBoss 7.1.1.Final

In a nutshell:

Encountering a LazyInitializationException when trying to add objects to a detached entity (Employee) in my application. Utilizing a custom collection as a transfer object resolves the issue.

Detailed Explanation:

I have an entity named Employee which includes a collection of Locations:

@Data
@EqualsAndHashCode(callSuper = true, of = {})
@ToString(callSuper = true, of = {})
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Employee extends Person
{
    @ManyToMany
    @JoinTable(name = "location_employee",
            joinColumns = @JoinColumn(name = "employee_id",
                    referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "location_id",
                    referencedColumnName = "id"))
    private Set<Location>   locations   = new HashSet<Location>();
}

The Employee class inherits from Person which contains attributes such as name, but they are irrelevant for this scenario.

@Data
@EqualsAndHashCode(of = "id")
@ToString(of = { "id", "name" })
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Person
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Setter(AccessLevel.NONE)
    private Long    id;

    private String  name;
}

The Location class is simple as well:

@Data
@EqualsAndHashCode(of = "id")
@ToString(of = { "id", "name" })
@Entity
public class Location
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Setter(AccessLevel.NONE)
    private Long            id;

    private String          name;
    @ManyToMany
    @JoinTable(name = "location_employee",
            joinColumns = @JoinColumn(name = "location_id",
                    referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "employee_id",
                    referencedColumnName = "id"))
    private Set<Employee>   employees = new HashSet<Employee>();
}

All collections default to lazy loading. However, when attempting to modify the locations collection of an Employee, a LazyInitializationException is thrown. Using a different collection for data transfer purposes mitigates this issue.

To eager load the Employee for manipulation on a JSF page, I use the following backing bean:

@Named
@Scope("view")
public class BackingBean
{
    @Inject
    private EmployeeDAO employeeDAO;
    private Employee        employeeFull;
    @Inject
    private LocationDAO locationDAO;
    private List<Location> locations;

    public Employee getSelectedEmployeeFull()
    {
        if (selectedEmployeeFull == null)
        {
            selectedEmployeeFull = employeeDAO.getEagerById(1L);
        }
        return selectedEmployeeFull;
    }

    public void setEmployeeFull(Employee e)
    {
        employeeFull = e;
    }

    public List<Location> getLocations()
    {
        if (locations == null)
        {
            locations = locationDAO.getAll()
        }
        return locations;
    }

    //...
} 

The EmployeeDAO class defines the query for eager loading:

@Named
public class EmployeeDAO
{
    @Inject
    private SessionFactory sessionFactory;

    @Transactional(readOnly = true)
    public Employee getEager(Long id)
    {
        Query q = sessionFactory.getCurrentSession().createQuery("select e from Employee e join fetch e.locations where e.id = :id");
        q.setParameter("id", id);
        try
        {
            return (Employee) q.uniqueResult();
        }
        catch (NonUniqueObjectException ex)
        {
            //Exception handling
            return null;
        }
    }
}

The JSF snippet that implements the functionality:

<p:dialog dynamic="true">
    <h:form>
        <p:selectCheckboxMenu label="Locations" value="#{employeeBean.employeeFull.locations}">
            <f:selectItems var="location" itemLabel="#{location.name}" value="#{employeeBean.locations}" />
        </p:selectCheckboxMenu>

        <p:commandButton value="save" action="#{employeeBean.update}"/>
    </h:form>
</p:dialog>

When launching the dialog, it properly loads the employeeFull property and populates the selectCheckboxMenu with existing Locations associated with the Employee.

However, upon submitting the form by clicking save without making any changes triggers a LazyInitializationException pertaining to the Employee.locations collection:

Error message goes here...

The EmployeeBean.update method is not invoked, evidenced by the absence of any breakpoint hits.

Now for the grand finale: How can I prevent this LazyInitializationException.

UPDATE

A temporary solution has been devised, although not necessarily optimal:

In the JSF page:

<p:dialog dynamic="true" onShow="loadSelectedEmployee()">
    <h:form>
        <p:remoteCommand action="#{employeeBean.loadSelectedEmployee}" name="loadSelectedEmployee" update=":editEmployeeDialogContent" />
    </form>
    <p:outputPanel layout="block" id="editEmployeeDialogContent">
        <h:form rendered="#{employeeBean.selectedEmployeeLoaded}">
            <p:selectCheckboxMenu label="Locations" value="#{employeeBean.selectedEmployee.locations}">
                <f:selectItems var="location" itemLabel="#{location.name}" value="#{employeeBean.locations}" />
            </p:selectCheckboxMenu>

            <p:commandButton value="save" action="#{employeeBean.update}"/>
        </form>
    </p:outputPanel>
</p:dialog>

In the backing bean:

public void loadSelectedEmployee()
{
    if (!selectedEmployeeLoaded)
    {
        selectedEmployee.setLocations(locationManager
                .getByEmployee(selectedEmployee));
        selectedEmployee.setRoles(roleManager
                .getByEmployee(selectedEmployee));
        selectedEmployeeLoaded = true;
    }
}

Answer №1

I suspect there may be a bug in either Primefaces or Jboss-jsf-api-2.1 causing this issue. Even though I can directly modify the PersistentSet in the controller, indicating that it is eager loaded, when binding it to the JSF component (specifically a Primefaces selectCheckboxMenu), it still throws a LazyInitializationException.

Answer №2

When performing a HQL query on an entity that lacks a relationship marked as "eager", the default behavior will be "lazy" loading, meaning the data will be queried at the time of retrieval.

To force initialization of the relationship in such cases, you can use the following example:

Hibernate.initialize(e.getLocations());

Here is how it can be integrated into your code:

@Transactional(readOnly = true)
public Employee getEager(Long id)
{
    Query q = sessionFactory.getCurrentSession().createQuery("select e from Employee e join fetch e.locations where e.id = :id");
    q.setParameter("id", id);
    try
    {
        final Employee e = (Employee) q.uniqueResult();
        if(e != null){
            Hibernate.initialize(e.getLocations());
        }
        return e;

    }
    catch (NonUniqueObjectException ex)
    {
        //Exception logging/handling
        return null;
    }
}

Best regards,

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Updating the button's appearance after submission using jQuery and Django

I have implemented an ajax "follow" button on my website. Currently, the button's attribute disabled changes to "disabled" after submission. However, I would like to modify the button from "follow" to "unfollow" upon submission, similar to how it work ...

Why does my ajax call always send a GET request instead of a POST?

$.ajax({ type:"post", url: server_url, dataType: "jsonp", jsonpCallback: callback, data:req_json, cache: false, timeout: 60000, success: succeeded, error: got_error }); I've ...

Having trouble displaying JSON response in Firefox console with Django

Code Snippet: from .views import get_data app_name = 'javascript' urlpatterns = [ path('', views.index, name='index'), path('api/data', get_data, name='api-data'), ] Views.py: from django.http ...

Performing two ajax calls within a non-existent div that has only just been appended

I've been developing a website similar to 9gag. I attempted to incorporate a voting feature created by someone else, as I'm not well-versed in AJAX requests, but it just doesn't seem to be functioning. My index.php file fetches five posts f ...

Refreshing a jsp page without the need to reload the content

On my jsp page, I am displaying the contents of a constantly changing table. This means that users have to refresh the page every time they want to see updated information. Is there a way for me to update the content dynamically without requiring users t ...

Safari causing issues with AJAX requests when using HTTPS

While I'm not an expert in ajax, the request I have is quite simple: $.ajax({ url: "https://62.72.93.18/index.php?a=get_lights", dataType: 'jsonp', success: function (res) { notify ? jsonLightsDone(re ...

Error encountered: JSON data contains an unexpected character at line 1, column 2

One of my PHP scripts looks like this: $STL = array(); $filter = array(); $filter['sort_by'] = "date_added"; $filter['sale'] = "F"; $filter['per_page'] = "12"; $STL['filter'] = $filter; echo json_encode($STL); When ...

Difficulty encountered while transmitting the JSON object to third-party API

Initially, the API structure is beyond my control and all I can do is make a simple call to it. Here are the required parameters to pass in: { "ConsumerAggregatedAttributes": [ { "ConsumerAggregatedAttribut ...

The perfect solution to easily access an extensive collection of Australian suburbs' databases through a comprehensive API

Is there a specific API available that provides an extensive collection of suburbs, especially in Australia? It should support AJAX auto-suggest functionality, allowing users to receive immediate suggestions as they type into the text box. ...

Leveraging Ajax in Django to communicate with the backend and showcase the outcome

I need assistance with implementing ajax functionality to send user input to a Django backend for text processing, and then display the results. However, due to my limited experience with ajax, I'm struggling to figure out where I'm going wrong. ...

Progress bar indicating the loading status of an AJAX script

I am facing a challenge with creating a progress bar in AJAX. The entire page is loaded through AJAX, and one of the webpage elements uses AJAX to fetch large rows from the database. I have attempted to implement a progress bar within this script using a ...

The AJAX validation process fails to run prior to the execution of the login PHP script

My attempt to implement AJAX for form validation is not successful and I'm unsure why. Despite my efforts, the form still redirects to login_action.php instead of performing the AJAX validation as intended. I have designed a modal login form and wish ...

Discover an Effective Approach for Transmitting Form-Data as a JSON Object

Hey there! I'm encountering a bit of an issue with sending some data as a JSON object. The problem arises when trying to send images using FormData. It seems like I need to convert my form data into a single JSON object. Can anyone assist me with this ...

Refreshing div content on selection change using PHP ajax with Jquery

Here is my code for the portfolio.php file <select name="portfolio" id="portfolio_dropdown" class="service-dropdown"> <?php foreach($years as $year){ ?> <option value="<?php echo $year[&apo ...

Having trouble invoking the controller method through an Ajax request

Controller: [HttpDelete] public void RemoveState(string id) { int stateId = Convert.ToInt32(id); var db = new ClubDataContext(); var stateInfo = from record in db.StateInfos where record.S_ID == stateId select record; ...

Looping through the Ajax calls until the final value is returned

While making an Ajax call, the returned value is always the last one. This issue has me stumped. Below is the code snippet: if(f_ref==209){ array1=[1,2,3,4,5,6]; for(var i = 0; i < array1.length; i++) { console.log("loo ...

Using jQuery's ajax function to send data with a variable name of data field

I am trying to figure out how to dynamically add a variable to the name of the data field I want to send information to through ajax. Below is an example of the code I'm working on: var qty = $('#qty_'+value).val(); $.ajax({ url: &apo ...

Working with variables passed from Node.js in Jade processing

Currently, I have a situation where my script is sending a matrix that looks like this: [[1,2,3,4], [7,6,5,4], [2,3,4,5]]. After sending it using res.send(JSON.stringify(dataArray)); and viewing it in jade with h1#results, I can see that the format appears ...

Generating URL parameters for Ajax requests on the fly

My current project involves creating a dynamic form where the number of fields displayed changes based on the user's selection from a dropdown menu. This means that depending on what option they choose, anywhere from 2 to 20 different fields may be sh ...

A guide to resolving cross-origin resource sharing issues using a reverse proxy

After creating a JavaScript web application for processing documents, I am now looking to integrate with web services like NLTK-server, TIKA-server, and SOLR for further analysis. While I can successfully access the REST endpoints of these services using c ...