0

I save current user in session, and when i use current user (example:user.getRole.getRoleName()), i got LIE. How can i solve this problem, my code is like this

Controller:

public String home(){
    Users users = userService.getCurrentUser();
    if(users.getRole().getRoleName().equals("admin")){ //causing LIE
    ....
}

UserService :

@Override
public Users getCurrentUser(){
    session =  ActionContext.getContext().getSession();
    return (Users) session.get("user");
}

But, when i change userService.getCurrentUser() to be like this, error is resolved but i think this is not a right manner, because it need connection to database every time i use current user.

@Override
public Users getCurrentUser(){
    session =  ActionContext.getContext().getSession();
    return daoManager.getDetailUser(((Users) session.get("user")).getUsername());
}

DaoManager.getDetailUser is like this

@Override
public Users getDetailUser(String username) {
    try {
        Users user = (Users)sessionFactory.getCurrentSession().createQuery("SELECT U FROM Users U WHERE U.username=:USERNAME")
             .setParameter("USERNAME", username)
             .uniqueResult();
        return user;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

is there any other better way to solve this problem? Thank you.

Mahadi Siregar
  • 565
  • 2
  • 14
  • 36

2 Answers2

1

The most likely explanation will be that Spring closes the current session when you are exiting the service layer (UserService), however, after this happens, because Hibernate attempts to lazily load the children objects to avoid unnecessarily loading data (see also What is lazy loading in Hibernate?).

To avoid this, you could either ensure that hibernate does not do lazy loading by specifying fetch=FetchType.EAGER on the role, or use the OpenSessionInView pattern (however, that's sometimes considered an antipattern, see Why is Hibernate Open Session in View considered a bad practice?).

Community
  • 1
  • 1
beny23
  • 32,077
  • 3
  • 78
  • 83
1

The easiest way to resolve this is just to access the lazy fetched field before the session is closed:

@Override
public Users getCurrentUser(){
    session =  ActionContext.getContext().getSession();
    Users user = (Users) session.get("user");
    user.getRole(); //Accessed to resolve lazy field
    return user;
}

I do not recommend FetchType.EAGER. With that you cannot control access, it is always fetched whether you need it or not.. Add a few EAGER fields to your data model and suddenly your fetching the entire database for the simplest requests..

For queries you can also use JOIN FETCH

barsju
  • 4,358
  • 1
  • 17
  • 24
  • agree with you not to use FetchType.EAGER as all data will be loaded whether it needed or not. about user.getRole(); What if we need the deeper data, for example in other case, whether we will do it for every model? i'm affraid, ultimately this will be close to the FetchType.EAGER. Am i right? – Mahadi Siregar Apr 10 '12 at 16:36
  • Well you should organize your code so that you only fetch the nodes you will be needing in every case... – barsju Apr 10 '12 at 19:35
  • it's not work (get LIE) because there in no open session when code user.getRole(); executed. Is there any other way? – Mahadi Siregar Apr 12 '12 at 09:22