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
9
  • do you print phones attribute in your toString method in Person class ? Commented Jun 19, 2017 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: docs.jboss.org/hibernate/orm/4.1/javadocs/org/hibernate/… Depending on your database model choosing one of them can lead to performance issue. Commented Jun 19, 2017 at 11:30
  • @AbassA yes I do have toString in person Commented Jun 19, 2017 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 Commented Jun 19, 2017 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? Commented Jun 19, 2017 at 14:03

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.