3

I'm beginner at hibernate and try to learn eager and lazy loading

I know that if the hibernate session is closed and then I try to retrieve lazy data, then Hibernate will throw an exception.

Now, I've tried to load main entity(Instructor) in first session and then load dependent entity(Course) in a new separate session:

Main Class(Test Class)

public class EagerLazyDemo {
    public static void main(String[] args) {

        SessionFactory factory = new Configuration().configure("hibernate.cfg.xml")
                .addAnnotatedClass(Instructor.class)
                .addAnnotatedClass(InstructorDetail.class)
                .addAnnotatedClass(Course.class)
                .buildSessionFactory();

        Session session = factory.getCurrentSession();

        // Begin A Transaction
        session.beginTransaction();

        // Get The Instructor From DB
        Instructor theInstructor = session.get(Instructor.class, 1);

        // Commit Transaction
        session.getTransaction().commit();

        session.close();

        //------

        //new session
        session = factory.getCurrentSession();
        session.beginTransaction();

        //Get And Display Courses For The Instructor
        List<Course> courses = theInstructor.getCourses();
        printCourses(courses);

        session.getTransaction().commit();
        session.close();

    }

    private static void printCourses(List<Course> courses) {
        for (Course c : courses) {
            System.out.println(c);
        }
    }
}

but hibernate throw this exception:

Error:

Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.mehdisarf.hibernate.demo.entity.Instructor.courses, could not initialize proxy - no Session
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:606)
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218)
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585)
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149)
    at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:387)
    at com.mehdisarf.hibernate.demo.EagerLazyDemo.printCourses(EagerLazyDemo.java:55)
    at com.mehdisarf.hibernate.demo.EagerLazyDemo.main(EagerLazyDemo.java:42)

it says:

could not initialize proxy - no Session Although I have a session for loading dependent entity

These Are My Entity Classes:

Instructor Class (main entity)

@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;

    public Instructor() {
    }

    public Instructor(String firstName, String lastName, String email) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
    }

    public void addCourse(Course theCourse) {
        if (courses == null) {
            courses = new ArrayList<>();
        }

        this.courses.add(theCourse);
        theCourse.setInstructor(this);
    }

    public int getId() {
        return id;
    }

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

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public InstructorDetail getInstructorDetail() {
        return instructorDetail;
    }

    public void setInstructorDetail(InstructorDetail instructorDetail) {
        this.instructorDetail = instructorDetail;
    }

    public List<Course> getCourses() {
        return courses;
    }

    public void setCourses(List<Course> courses) {
        this.courses = courses;
    }

    @Override
    public String toString() {
        return id + "" + firstName + "" + lastName + "" + email + "  (Detail:" + instructorDetail+")";
    }
}

Course Class (dependent entity)

@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(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinColumn(name = "instructor_id")
    private Instructor instructor;

    public Course() {
    }

    public Course(String title) {
        this.title = title;
    }

    public int getId() {
        return id;
    }

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

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Instructor getInstructor() {
        return instructor;
    }

    public void setInstructor(Instructor instructor) {
        this.instructor = instructor;
    }

    @Override
    public String toString() {
        return id + "|" + title + "|";
    }
}
0

2 Answers 2

2

Your object theInstructor is still linked to the former session. In order to retrieve your object you have to make another call after opening the new session : theInstructor = session.get(Instructor.class, 1);

Sign up to request clarification or add additional context in comments.

Comments

1
+50

"theInstructor" is not attached to any session while "theInstructor.getCourses()" call is made, this results in exception.

When object is returned by the get method it is in the Persistent state.

Any instance returned by a get() or load() method is persistent Session Documentation

When session is closed "theInstructor" object goes into the Detached state.

Detached - a detached instance is an object that has been persistent, but its Session has been closed. Hibernate object states documentation

Call made to session = factory.getCurrentSession(); returns new session object, but theInstructor object is not attached to the new session. Hence an attempt to lazily load the courses fails.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.