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
System.out.println(persons);, it call the toString method for every persons in your list and since you try to print the phones in toString method of Person class you get the LazyInitializationException. So just remove phones attribute from toString. it should workreturn "Person [person_id=" + person_id ..... , phones=" + phones + "]";I am not calling getPhone method shouldn't just return null?