msmilkshake
msmilkshake

Reputation: 214

Hibernate - Why is lazy loading not working here?

I am learning Hibernate from an online course, and right now, I am learning Eager vs Lazy loading.

For the example I have three entities and a test program like so:

@Entity
@Table(name = "instructor")
public class Instructor {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;
    
    @Column(name = "first_name")
    private String firstName;
    
    @Column(name = "last_name")
    private String lastName;
    
    @Column(name = "email")
    private String email;
    
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "instructor_detail_id")
    private InstructorDetail instructorDetail;
    
    @OneToMany(fetch = FetchType.LAZY,
            mappedBy = "instructor",
            cascade = {
                    CascadeType.DETACH,
                    CascadeType.MERGE,
                    CascadeType.PERSIST,
                    CascadeType.REFRESH
            })
    private List<Course> courses;
    
    // constructors
    
    public void add(Course tempCourse) {
        if (courses == null) {
            courses = new ArrayList<>();
        }
        
        if (tempCourse != null) {
            courses.add(tempCourse);
            tempCourse.setInstructor(this);
        }
    }
    
    // getters and setters
    
    @Override
    public String toString() {
        return "Instructor{" +
                "id=" + id +
                ", firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", email='" + email + '\'' +
                ", instructorDetail=" + instructorDetail +
                '}';
    }
    
}
@Entity
@Table(name = "instructor_detail")

public class InstructorDetail {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;
    
    @Column(name = "youtube_channel")
    private String youtubeChannel;
    
    @Column(name = "hobby")
    private String hobby;
    
    @OneToOne(mappedBy = "instructorDetail",
            cascade = {
                    CascadeType.DETACH,
                    CascadeType.MERGE,
                    CascadeType.PERSIST,
                    CascadeType.REFRESH
            })
    private Instructor instructor;
    
    // constructors
    
    // getters and setters
    
    @Override
    public String toString() {
        return "InstructorDetail{" +
                "id=" + id +
                ", youtubeChannel='" + youtubeChannel + '\'' +
                ", hobby='" + hobby + '\'' +
                '}';
    }
    
}
@Entity
@Table(name = "course")
public class Course {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;
    
    @Column(name = "title")
    private String title;
    
    @ManyToOne(fetch = FetchType.LAZY,
            cascade = {
                    CascadeType.DETACH,
                    CascadeType.MERGE,
                    CascadeType.PERSIST,
                    CascadeType.REFRESH})
    @JoinColumn(name = "instructor_id")
    private Instructor instructor;
    
    // constructors
    
    // getters and setters
    
    @Override
    public String toString() {
        return "Course{" +
                "id=" + id +
                ", title='" + title + '\'' +
                '}';
    }
    
}

Main Program:

package pt.hmsk.hibernate.demo;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import pt.hmsk.hibernate.demo.entity.Course;
import pt.hmsk.hibernate.demo.entity.Instructor;
import pt.hmsk.hibernate.demo.entity.InstructorDetail;

public class EagerLazyDemo {
    
    public static void main(String[] args) {
        try (SessionFactory factory = new Configuration()
                .configure("hibernate.cfg.xml")
                .addAnnotatedClass(Instructor.class)
                .addAnnotatedClass(InstructorDetail.class)
                .addAnnotatedClass(Course.class)
                .buildSessionFactory();
             Session session = factory.getCurrentSession()) {
            
            // start a transaction
            session.beginTransaction();
    
            // get instructor from db
            int theId = 1;
            Instructor tempInstructor = session.get(Instructor.class, theId);
    
            System.out.println("luv2code: Instructor: " + tempInstructor);
            
            // get courses for the instructor
            System.out.println("luv2code: Courses: " + tempInstructor.getCourses());
            
            // commit transaction
            session.getTransaction().commit();
            
            System.out.println("luv2code: Done!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
}

Then, I put a breakpoint in the main program at the line:

System.out.println("luv2code: Instructor: " + tempInstructor);

Supposedly here, no call to the courses field was done yet so, it shouldn't be in the tempInstructor obejct, but debugging the program shows that the course was loaded into the Instructor obejct anyways: debugger

Why is this happening??

Upvotes: 1

Views: 283

Answers (2)

Valerij Dobler
Valerij Dobler

Reputation: 2764

Oh, another way to verify it, is to do the call to the courses after you've committed the transaction. The transaction is the scope, where lazy loading can happen.

Upvotes: 1

Valerij Dobler
Valerij Dobler

Reputation: 2764

You are lazy loading the courses, but because you are referencing them via the line

System.out.println("luv2code: Courses: " + tempInstructor.getCourses());

they are loaded in.

Turn on logging of the queries by adding to your hibernate.cfg.xml

<property name="hibernate.show_sql">true</property>

And don't get the courses from the Instructor, then you will see, that they were in fact lazy-loaded.

Upvotes: 2

Related Questions