"failed to lazily initialize a collection of role"

1.5k Views Asked by At

In my project, I use PostgreSQL and Hibernate to connect to my ZUL and all that noise. The connection I am trying to do is, in a Facebook manner, an user entry whose ID appears in several Posts and Comments. This calls for a OneToMany and a ManyToOne kind of deal. This is my first time doing these kind of connections in ZK and Hibernate, and I would appreciate it if I were pointed out where I'm wrong.

Here are the errors that pop out several times:

Caused by: org.zkoss.zel.ELException: org.hibernate.LazyInitializationException: could not initialize proxy - no Session
Caused by: org.hibernate.LazyInitializationException: could not initialize proxy - no Session
Grave:   org.zkoss.zk.ui.UiException: org.hibernate.LazyInitializationException: could not initialize proxy - no Session at [file:/C:/Users/Frank/Documents/Work/Fakebook_v3/build/web/index.zul, line:42]
Grave:   org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: pojos.Post.comments, could not initialize proxy - no Session

And here are the Post, Comment and FBUser java files:

@Entity
@Table(name = "post")
@org.hibernate.annotations.Entity(dynamicUpdate = true)
public class Post implements java.io.Serializable {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "postid", updatable = false, nullable = false)
private int postid;

@Column(name = "fbuser")
private Fbuser fbuser;

@Column(name = "info")
private String info;

@Column(name = "plikes")
private int plikes;

@Column(name = "comments")
@OneToMany(fetch = FetchType.EAGER, mappedBy = "post", cascade = CascadeType.ALL)
private Collection<Comment> comments = new LinkedHashSet<Comment>();

//getters, setters and other tools

@Entity
@Table(name = "comment")
@org.hibernate.annotations.Entity(dynamicUpdate = true)
public class Comment implements java.io.Serializable {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "commentid", updatable = false, nullable = false)
private int commentid;

@Column(name = "fbuser")
private Fbuser fbuser;

@Column(name = "post")
@ManyToOne
@JoinColumn(name="post", nullable=false)
private Post post;

@Column(name = "info")
private String info;

@Column(name = "clikes")
private int clikes;

//getters, setters and other tools

@Entity
@Table(name = "fbuser")
@org.hibernate.annotations.Entity(dynamicUpdate = true)
public class Fbuser implements java.io.Serializable {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "fbuserid", updatable = false, nullable = false)
private int fbuserid;

@Column(name = "name")
private String name;

@Column(name = "comments")
@OneToMany(fetch = FetchType.EAGER, mappedBy = "fbuser", cascade = CascadeType.ALL)
private Set<Comment> comments = new HashSet<Comment>(0);

@Column(name = "posts")
@OneToMany(fetch = FetchType.EAGER, mappedBy = "fbuser", cascade = CascadeType.ALL)
private Collection<Post> posts = new LinkedHashSet<Post>();

//getters, setters and other tools

And my connector with Hibernate is basically this code several times with different table names and ID's:

public List<Post> getPosts() throws Exception {
    session = HibernateUtil.getSessionFactory().openSession();
    session.beginTransaction();

    String toDo = "FROM Post ORDER BY postid DESC";

    List<Post> posts = session.createQuery(toDo).list();

    session.getTransaction().commit();
    session.close();
    return posts;
}

Any help is appreciated!

2

There are 2 best solutions below

0
Frank Vargas On BEST ANSWER

It was a surprise to know that my error wasnt in the controllers, but in the hbm.xml of the files Post, Comment and Fbuser. In those files, I have these lines in various ways:

<many-to-one name="fbuser" class="pojos.Fbuser" lazy="false" fetch="select">
    <column name="fbuser_id" not-null="true" />
</many-to-one>
<property name="info" type="string">
    <column name="info" length="300" not-null="true" />
</property>
<property name="plikes" type="int">
    <column name="plikes" not-null="true" />
</property>
<set name="comments" table="comment" inverse="true" lazy="false" fetch="select">
    <key>
        <column name="post_id" not-null="true" />
    </key>
    <one-to-many class="pojos.Comment" />
</set>

The problem came when I didnt added the attribute lazy="false" in the sets and many-to-one/one-to-many tags!

1
Col On

The problem is that the session is closed when you want to try to retrieve Fbuser's posts. Obviously eager loading isn't working with the way you are retrieving the data. You have a couple of options:

1) The dirty hack: actively load up the posts when you retrieve the Fbuser

String toDo = "FROM Fbuser ORDER BY fbuserid DESC";
List<Fbuser> fbusers = session.createQuery(toDo).list();
for (Fbuser fbuser : fbusers)
    Hibernate.initialize(fbuser.getPosts());

The downside of this is you might need to then loop through the posts and get the comments. Pretty ugly and potentially very time consuming if the there are a large number of users, posts and comments.

2) Do the query the hibernate way so that the eager loading is honoured:

public Fbuser getFbuserById(long fbuserid) {
    Session session = HibernateUtil.getSessionFactory().openSession();
    Fbuser fbuser = session.get(Fbuser.class, fbuserid);
    session.close();
    return fbuser;
}

Probably the best, and most efficient way, is to remove eager loading and retrieve the data as required which looks pretty close to what you're doing.