0

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

  1. 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?

  2. 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
Eric Huang
  • 1,114
  • 3
  • 22
  • 43
  • do you print phones attribute in your toString method in Person class ? – Abass A Jun 19 '17 at 11:21
  • Fetchmode is usefull when you need to specify how a relation must be fetched. Either by Join or Select FecthMode. Please see the doc: https://docs.jboss.org/hibernate/orm/4.1/javadocs/org/hibernate/FetchMode.html Depending on your database model choosing one of them can lead to performance issue. – Abass A Jun 19 '17 at 11:30
  • @AbassA yes I do have toString in person – Eric Huang Jun 19 '17 at 13:33
  • 1
    So it is the reason when you call `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 work – Abass A Jun 19 '17 at 13:49
  • @Abassa yes but when your toString method returns field like so `return "Person [person_id=" + person_id ..... , phones=" + phones + "]";` I am not calling getPhone method shouldn't just return null? – Eric Huang Jun 19 '17 at 14:03
  • `getPhones` is just public method to access your field from outside. so inside Person class it is the same to call phones directly ou getPhones() you try to access an object which is not initialized since session is closed. – Abass A Jun 19 '17 at 14:07
  • @AbassA Thank you very much. Removing the phone in toString method helps gets ride of the Exception. However now I have a jackson exception because during serialization jackson also tries to fetch... any work around? – Eric Huang Jun 19 '17 at 14:45
  • Ok good, i suggest you to create another post since for this one the pb is solved. – Abass A Jun 19 '17 at 15:00
  • okey marked as answer... thank you – Eric Huang Jun 19 '17 at 15:03

1 Answers1

2

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.

Abass A
  • 713
  • 6
  • 14