Lazy associations cannot be fetched for the detached entities. Lazy fetching is desired when associated entities are not likely to be accessed right after the loading of the parent entity. They are usually accessed conditionally and may be after a long time of their parent entity loading. To access lazy relationships of the detached entities, we have to attach them back to the persistence context by using EntityManager.merge() method. Let's understand that with an example.
Example
The Entities
@Entity
public class Person {
@Id
@GeneratedValue
private long id;
private String name;
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<Phone> phoneList;
.............
}
@Entity
public class Phone {
@Id
@GeneratedValue
private long id;
private String number;
private String type;
.............
}
Fetching detached entity's lazy relationship
public class ExampleMain {
static EntityManagerFactory emf =
Persistence.createEntityManagerFactory("example-unit");
public static void main(String[] args) throws Exception {
try {
long id = persistPerson();
Person person = loadPersonById(id);
person.getPhoneList().forEach(System.out::println);
} finally {
emf.close();
}
}
private static Person loadPersonById(long id) {
EntityManager em = emf.createEntityManager();
Person person = em.find(Person.class, id);
em.close();
return person;
}
private static long persistPerson() {
Person person = new Person();
person.setName("Jackie");
person.addPhone("111-11-1111", "cell");
person.addPhone("22-222-2222", "work");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(person);
em.getTransaction().commit();
em.close();
return person.getId();
}
}
Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.logicbig.example.Person.phoneList, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:582)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:201)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:561)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:132)
at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:277)
at java.lang.Iterable.forEach(Iterable.java:74)
at com.logicbig.example.ExampleMain.main(ExampleMain.java:17)
Since lazy fetching is only a hint and can be ignored by a JPA provider, this behavior might not be consistent for different providers.
To fix above exception, we need to use merge() method and fetch the lazy data within the EntityManager context (before calling close() ).
public class ExampleMain2 {
static EntityManagerFactory emf =
Persistence.createEntityManagerFactory("example-unit");
public static void main(String[] args) throws Exception {
try {
long id = persistPerson();
Person person = loadPersonById(id);
List<Phone> phoneList = mergeAndGetPhoneList(person);
phoneList.forEach(System.out::println);
} finally {
emf.close();
}
}
private static List<Phone> mergeAndGetPhoneList(Person person) {
EntityManager em = emf.createEntityManager();
person = em.merge(person);
List<Phone> phoneList = person.getPhoneList();
em.close();
return phoneList;
}
.............
} OutputPhone{id=2, number='111-11-1111', type='cell'} Phone{id=3, number='22-222-2222', type='work'}
Example ProjectDependencies and Technologies Used: - hibernate-core 5.2.8.Final: The core O/RM functionality as provided by Hibernate.
Implements javax.persistence:javax.persistence-api version 2.1 - h2 1.4.193: H2 Database Engine.
- JDK 1.8
- Maven 3.3.9
|