Monday, August 12, 2013

Lazy loading not wotking with hibernate OneToOne mapping

in my experience, i have encountered an issue that the hibernate lazy loading is not working when we map the relationship between two entities  using OneToOne annotations.see the following examples.

Lecturer.java

package com.chathurangaonline.examples.model;



import javax.persistence.*;

import java.io.Serializable;



@Entity
@Table(name = "Lecturer")
public class Lecturer implements Serializable{

    @Id
    @GeneratedValue
    @Column(name = "id")
    private Long id;


    @OneToOne(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
    @JoinColumn(name = "course_id")
    private Course course;


    public Long getId() {
        return id;
    }


    public void setId(Long id) {
        this.id = id;
    }


    public Course getCourse() {
        return course;
    }


    public void setCourse(Course course) {
        this.course = course;
    }
}





Course.java

package com.chathurangaonline.examples.model;


import javax.persistence.*;
import java.io.Serializable;


@Entity
@Table(name = "Course")
public class Course implements Serializable{

    @Id
    @GeneratedValue
    @Column(name = "id")
    private Long id;


    @Column(name = "course_name")
    private String courseName;


    @OneToOne(fetch = FetchType.LAZY,mappedBy = "course")
    private Lecturer lecturer;


    public Long getId() {
        return id;
    }


    public void setId(Long id) {
        this.id = id;
    }


    public String getCourseName() {
        return courseName;
    }


    public void setCourseName(String courseName) {
        this.courseName = courseName;
    }


    public Lecturer getLecturer() {
        return lecturer;
    }


    public void setLecturer(Lecturer lecturer) {
        this.lecturer = lecturer;
    }
}



you will notice that the mapping from the lecturer to course is One-To-One and the fetch type is LAZY. Since the fetch type is LAZY, the associated course object should not be loaded when the lecturer object is loaded. the associated course object should be loaded only when the user request it. that is the behavior of the lazy fetch mode.

    but in this example, you will notice that course object is loaded (EAGER resolved) when the time that the lecturer object is loaded regardless of the LAZY fetch type. it always eagerly resolve the associated entities even if it is declared as LAZY fetch. . please refer the below screenshot.


you will see that when retrieving the Lecturer object with given id, it generates and issue a SQL query to retrieve data from the database. when the lecturer object is retrieved, it loads and populates the associated course object also. that is why when we request the course object and its attributes, it directly give the values of the attributes without issuing another SQL query. the reason for this EAGER behavior can be described as follows.


    @OneToOne(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
    @JoinColumn(name = "course_id")
    private Course course;

you will notice that the OneToOne relationship is not mandatory and it is optional.(by default, the optional=true). since the relationship is optional, hibernate(ORM framework) does not know whether the given lecturer teach a course or not without issuing an another query. therefore hibernate cannot populate the course reference with a proxy, because it does not know whether a course exists for that lecturer.  On the other hand, it cannot populate the course attribute with null because, there may be lecturers who teach courses. therefore hibernate performs the EAGER loading regardless of the LAZY fetch mode if the relationship is OneToOne and it is optional.

to overcome to above issue and make the LAZY loading working, you need to make the relationship as mandatory. In oder to do that, set the optional=false.

   @OneToOne(fetch = FetchType.LAZY,
                        cascade = CascadeType.ALL,
                        optional = false)
   @JoinColumn(name = "course_id")
   private Course course;



then the lazy loading should works as usual.
refer the following screenshot and identify how the lazy loading works. refer the below screenshot.


you will see that when retrieving the associated course instance from the lecturer instance, it generates another SQL queries to retrieve the course details associated. this is because the Fetch type of the relationship is LAZY.


references :
http://stackoverflow.com/questions/17987638/hibernate-one-to-one-lazy-loading-optional-false


Hope this will be helpful for you!

Thanks
Chathuranga Tennakoon
chathuranga.t@gmail.com
www.chathurangaonline.com







1 comment: