Reputation: 1264
I am just starting to learn about FetchType Lazy and Eager. I understand the difference but even if I set to Lazy its somehow still trying to get the associated data.
Relationship: 1 Person : Many Phones
Research attempts and tutorials viewed:
https://www.mkyong.com/hibernate/hibernate-one-to-many-relationship-example-annotation/ http://howtodoinjava.com/hibernate/lazy-loading-in-hibernate/ https://howtoprogramwithjava.com/hibernate-eager-vs-lazy-fetch-type/
I understand to get the associated data I will need to do it while still in session() So for my particular example In my Dao I will need something like this
List<Person> persons = criteria.list();
for(Person person : persons){
Set sets = person.getPhones();
}
return persons;
So far correct?
But the problem is I am not calling person.getPhones() anywhere not in Dao, controller..etc but I am getting LazyInitializationEception. For the life of me can't seem to catch what is wrong.
Stack trace
Jun 19, 2017 2:24:01 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [app-dispatcher] in context with path
[/uni-starter-onetomany] threw exception [Request processing failed; nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.app.person.Person.phones, could not initialize proxy - no Session] with root cause
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.app.person.Person.phones, could not initialize proxy - no Session
Person.class
@Entity
@Table(name="person")
@Component
public class Person {
@Id
@GeneratedValue
private int person_id;
private String name;
private String age;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "person")
private Set<Phone> phones;
// Getter and setters
// ToString method by field name not by method
Phone.class
@Entity
@Table(name="phone")
@Component
public class Phone {
@Id
@GeneratedValue
private int phone_id;
private String type;
private String phone;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="person_person_id")
private Person person;
// Getter and setters
PersonDao
@Repository
@Transactional
@Component("personDao")
public class PersonDao {
@Autowired
private SessionFactory sessionFactory;
public Session session(){
return sessionFactory.getCurrentSession();
}
public List<Person> getPersonList(){
Criteria criteria = session().createCriteria(Person.class);
List<Person> persons = criteria.list();
// for(Person person : persons){
//
// Set sets = person.getPhones();
//
// }
return persons;
}
public void saveOrUpdate(Person person){
session().saveOrUpdate(person);
}
}
Controller
// Get list
@RequestMapping(path="/list", method = RequestMethod.GET, produces="application/json")
@ResponseBody
public Map<String, Object> getListPerson(){
Map<String, Object> data = new HashMap<String, Object>();
List<Person> persons = personDao.getPersonList();
data.put("results", persons);
System.out.println(persons);
return data;
}
Question
As long as I don't call person.getPhones() within the session it should only return person? if so what might be the problem here that I am getting LazyInitializationException?
I also seen people setFetchMode() FetchMode.JOIN in the Dao class for example Hibernate Criteria Join with 3 Tables perhaps this could be subjective but what would be a better practice? any performance issues?
Any idea, links or articles are much appreciated...
UPDATE Thanks to Abassa removing Phone in from toString in Person.class fixes the problem. But I just realize that due to Jackson, during serialization it tries to fetch Phone ojbect.... is there a work around?
Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: failed to lazily initialize a collection of role: com.app.person.Person.phones, could not initialize proxy - no Session
Upvotes: 0
Views: 804
Reputation: 743
Remove phones field from toString method in Person class.
When you call:
System.out.println(persons);
you try to access phones fields because println calls toString method for every person in the list so you get the LazyInitializationException.
Upvotes: 2