Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate - failed to lazily initialize a collection of role - could not initialize proxy - no Session

Issue: Cannot add Address object via User object inside a Spring Controller.

User and Address classes -> @Entity

User has a List<Address> with FetchType=LAZY

@Repository
public class UserDao{
    @Autowired
    private SessionFactory sessionFactory;
    ...
    public User get(String username) {
        Session session = sessionFactory.getCurrentSession();
        return (User)session.get(User.class, username);
    }
    ...
    public void update(User user){
        Session session = sessionFactory.getCurrentSession();
        session.saveOrUpdate(user);
    }
    ...
}


@Service
@Transnational
public class UserService{
    @AutoWired
    private UserDao userDao;
    ...

    @Transactional(readOnly = true)
    public User get(String username) {
        Session session = sessionFactory.getCurrentSession();
        return (User)session.get(User.class, username);
    }

    public void update(User user){
        userDao.update(user);
    } 
    ...
}

@Controller
public class UserController{
    @AutoWired
    private UserService userService;
    ....
    public String update(){
        User user = userService.get("user0001");
        user.getAddressList.add(new Address("new street"));
        return "update";
    }
}

Spring.xml

<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location">
        <value>classpath:jdbc.properties</value>
    </property>
</bean>

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${jdbc.driverClassName}" />
    <property name="jdbcUrl" value="${jdbc.url}" />
    <property name="user" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource">
        <ref bean="dataSource"/>
    </property>
    <property name="packagesToScan" value="com.entity" />
    <property name="hibernateProperties">
       <props>
         <prop key="hibernate.dialect">${hibernate.dialect}</prop>
         <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
       </props>
    </property> 
</bean>

Everything is working fine. But I cannot make changes to the user object inside a @Controller.

When user object is getting change in @Controller level, there is no such Hibernate session involves with the object. Somehow the object is out of the hibernate context.

Error happens at .add(new Address("new street")); statement in @Controller.

Why it is prohibited to change an object inside a Controller which is received via Hibernate session?

The way I followed is incorrect? If not what have I done wrong?

--Spring 4, Hibernate 4

like image 325
user2172625 Avatar asked Jan 24 '26 11:01

user2172625


1 Answers

User has a List<Address>. When you fetch the user from the database rather then a list, hibernate inserts a proxy that handles the fetching of the addresses.

This proxy needs to have a session to be able to do anything. When you try to add an address you are outside the scope of the transactional annotation, thus there is no session.

Best way to get you going would be to add a method annotated with @Transactional in the UserService that adds an address.

like image 144
M.P. Korstanje Avatar answered Jan 26 '26 03:01

M.P. Korstanje