I work on a small project and I have 2 tables, User and Application. A user can have multiple applications and an application might be used by multiple user, so it is a many-to many relation between them. Each table has some fields(id, name, password, technologies etc) and I also declared 2 arraylists both in User and Application class with the @ManyToMany adnotation. Problem is that in my Business Layer i wrote a method which should add an application to a user and when I try to do user.getListOfApplications().add(app) it gives me that exception...
public class ManagerHibernate { private SessionFactory sessionFactory;
public void setup()
{
sessionFactory = new Configuration().configure().buildSessionFactory();
}
public void exit()
{
sessionFactory.close();
}
public void create(Object obj)
{
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(obj);
session.getTransaction().commit();
session.close();
}
public Object read(Class<?> c, int idObj)
{
Session session = sessionFactory.openSession();
session.beginTransaction();
Object obj = session.get(c, idObj);
System.out.println(obj);
session.getTransaction().commit();
session.close();
return obj;
}
public void update(Object obj)
{
Session session = sessionFactory.openSession();
session.beginTransaction();
session.update(obj);
session.getTransaction().commit();
session.close();
}
public void delete(Object obj)
{
Session session = sessionFactory.openSession();
session.beginTransaction();
session.delete(obj);
session.getTransaction().commit();
session.close();
}
public <T> List<T> loadAllData(Class<T> type)
{
Session session = sessionFactory.openSession();
session.beginTransaction();
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<T> criteria = builder.createQuery(type);
criteria.from(type);
List<T> data = session.createQuery(criteria).getResultList();
session.getTransaction().commit();
session.close();
return data;
}
}
public Boolean addNewApplicationToUser(String userUserName, String applicationName)
{
int okUser = 0;
int okApp = 0;
listOfApplications = managerHibernate.loadAllData(Application.class);
listOfUsers = managerHibernate.loadAllData(User.class);
User user = null;
Application app = null;
for(Application index: listOfApplications)
{
if(index.getApplicationName().equals(applicationName))
{
okApp = 1;
app = index;
}
}
for(User index: listOfUsers)
{
if(index.getUserUserName().equals(userUserName))
{
okUser = 1;
user = index;
}
}
if(okUser == 0 || okApp == 0)
return false;
else
{
user.getListOfApplications().add(app);
//app.getUserList().add(user);
return true;
}
}
The method addNewApplicationToUser is written in another class called ControllerHibernate. Only the else branch is important, the rest is to check if the parameters do actually exist in the database
The issue starts when you are loading data with the following method managerHibernate.loadAllData
public <T> List<T> loadAllData(Class<T> type)
{
// New session was opened here
Session session = sessionFactory.openSession();
session.beginTransaction();
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<T> criteria = builder.createQuery(type);
criteria.from(type);
List<T> data = session.createQuery(criteria).getResultList();
session.getTransaction().commit();
session.close();
//session is close here
return data;
}
So when you are loading data the hibernate framework will only load the user object. Since you have opted to use lazy loading in your model class the application values will be loaded only when your try to access the list. Since you have already closed your session the framework can no longer get the application list resulting in lazy loading exception.
listOfApplications = managerHibernate.loadAllData(Application.class);
//loading user data and close the session associated with it
listOfUsers = managerHibernate.loadAllData(User.class);
User user = null;
Application app = null;
for(Application index: listOfApplications)
{
if(index.getApplicationName().equals(applicationName))
{
okApp = 1;
app = index;
}
}
for(User index: listOfUsers)
{
if(index.getUserUserName().equals(userUserName))
{
okUser = 1;
user = index;
}
}
if(okUser == 0 || okApp == 0)
return false;
else
{
// when you run this line the hibernate framework will try to retrieve the application data.Since you have the closed session lazy load exception occurs
user.getListOfApplications().add(app);
return true;
}
Ways to overcome this issue
1) Try to keep your session open so that the application data is can be fetched by your framework
2) Change lazy loading to eager loading in your model pojo class (Since you are using many to many relationship not advisable to use this way)