Engineering Full Stack Apps with Java and JavaScript
We will see a simple example to illustrate the LAZY and EAGER Fetch in Hibernate.
We will have a User class that refer to an Address class, and a test class. If you are not following the tutorials in order, refer to the article http://javajee.com/your-first-hibernate-program-using-hibernate-43 for the basic setup including hibernate configuration file and refer to http://javajee.com/embedding-value-types-within-an-entity-class-in-hibernate-43 for the Address class.
Initially the user class will use an empty @ElementCollection annotation to refer to the embedded collection.
The User class will look as:
package com.javajee.hiberex.dto;
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
@Entity
public class User {
@Id
int id;
private String name;
@ElementCollection
private Collection<Address> addresses = new ArrayList<Address>();
//Getters and setters not shown, you can refer to other tutorials or generate it in eclipse.
}
We will use the same Address class from http://javajee.com/example-lab-embedding-value-types-within-an-entity-cl....
In the test class, after retrieving user, we will close session and then try to print the values of the embedded collection.
The test class will look as below:
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.javajee.hiberex.dto.Address;
import com.javajee.hiberex.dto.User;
public class UserTest {
public static void main(String[] args) {
User u = new User();
u.setId(1);
u.setName("Heartin");
Address addr = new Address();
addr.setHouseno(777);
addr.setStreet("MyStreet");
u.getAddresses().add(addr);
u.getAddresses().add(addr);
Configuration configuration = new Configuration();
configuration.configure();
ServiceRegistry serviceRegistry = StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build();
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(u);
session.getTransaction().commit();
u = null;
session = sessionFactory.openSession();
session.beginTransaction();
u = (User) session.get(User.class, 1);
session.getTransaction().commit();
session.close();
for(Address add : u.getAddresses()){
System.out.println(add.getHouseno());
}
}
}
If you execute this code, you will get this exception:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection…
This is because when you call session.get for user, only user fields (except the address list collection) is retrieved.
We are then trying to print the address details after session.close, but after session.close there is no session available to retrieve the address details lazily and hence it throws an exception.
If you change the @ElementCollection annotation to @ElementCollection (fetch=FetchType.LAZY), the behavior will be same and you will still get org.hibernate.LazyInitializationException.
This is because FetchType.LAZY is the default.
Now change the @ElementCollection annotation to @ElementCollection (fetch=FetchType.EAGER) in User class as:
…
@ElementCollection (fetch=FetchType.EAGER)
private Collection<Address> addresses = new ArrayList<Address>();
…
Execute the same TestUser class and you will get a successful response this time.
This is because in EAGER initialization, you retrieve the collection during session.get for user and not retrieved after session.close.