I have a User model with a lazily-loaded Sites collection:
@Entity
public class User {
@Id
@GeneratedValue
private Integer id;
@OneToMany(fetch = FetchType.LAZY)
private Set<Site> sites;
...
and a HQL query in my UserDao which loads a user by id, and also fetches the associated sites:
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Query;
import org.springframework.stereotype.Repository;
@Repository
public class userDaoImpl implements UserDao() {
@Inject
private SessionFactory sessionFactory;
public Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
public User findByIdFetchSites(final Integer id) {
String queryString = "SELECT user FROM User user LEFT JOIN FETCH user.sites WHERE user.id = :id";
Query qry = getCurrentSession().createQuery(queryString).setInteger("id", id);
return qry.uniqueResult();
}
...
I want to test that the sites are being fetched along with the user when I run this Dao method. I have a JUnit test class running against HSQLDB, as follows:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:/test-context.xml" })
@DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD)
@Transactional
public class UserDaoImplTest {
@Inject private UserDaoImpl userDaoImpl;
@Test
public void retrievesUserFetchesSites() {
Set<Site> sites = new HashSet<Site>();
...
User user = new User();
user.setSites(sites);
userDaoImpl.saveOrUpdate(user);
User retrievedUser = userDaoImpl.findByIdFetchSites(1);
assertTrue(retrievedUser.getSites().containsAll(sites));
}
Where @Transactional is the spring transactional annotation (org.springframework.transaction.annotation.Transactional). The test passes even when I run it against a simple findUserById DAO method, for which the sites are not explicitly fetched:
public User findById(final Integer id) {
String queryString = "SELECT user FROM User user WHERE user.id = :id";
Query qry = getCurrentSession().createQuery(queryString).setInteger("id", id);
return qry.uniqueResult();
}
I'm not entirely sure why the sites are being fetched before the assertion (I can't see it in a select statement in the logs), but what I think I want to do is close the current session before the assertion occurs; something like:
@Test
public void retrievesUserFetchesSites() {
Set<Site> sites = new HashSet<Site>();
...
User user = new User();
user.setSites(sites);
userDaoImpl.saveOrUpdate(user);
User retrievedUser = userDaoImpl.findByIdFetchSites(1);
userDaoImpl.getCurrentSession().close();
assertTrue(retrievedUser.getSites().containsAll(sites));
}
However, when I tried this I got the following exception:
org.springframework.transaction.TransactionSystemException: Could not roll back Hibernate transaction; nested exception is org.hibernate.TransactionException: rollback failed
at org.springframework.orm.hibernate4.HibernateTransactionManager.doRollback
which I assume is due to @DirtiesContext (I need a clean db before each test). How can I ensure that hibernate doesn't do lazy loading for my associations during the test?