我有一个带有延迟加载的网站集的用户模型:
@Entity
public class User {
@Id
@GeneratedValue
private Integer id;
@OneToMany(fetch = FetchType.LAZY)
private Set<Site> sites;
...
和我的UserDao中的HQL查询,它通过id加载用户,并且还提取关联的站点:
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();
}
...
我想在运行此Dao方法时测试网站是否与用户一起提取。我有一个针对HSQLDB运行的JUnit测试类,如下所示:
@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));
}
其中@Transactional是spring transactional annotation(org.springframework.transaction.annotation.Transactional)。即使我在一个简单的findUserById DAO方法上运行它,测试也会通过,对于这个方法,没有显式获取站点:
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();
}
我不完全确定为什么在断言之前提取网站(我无法在日志中的select语句中看到它),但我认为我想做的是在断言之前关闭当前会话发生;类似的东西:
@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));
}
然而,当我尝试这个时,我得到以下异常:
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
我假设是由于@DirtiesContext(我在每次测试之前需要一个干净的数据库)。如何在测试期间确保hibernate不会为我的关联进行延迟加载?
答案 0 :(得分:5)
问题在于,在同一事务中,您创建一个包含站点的用户,然后检索此用户。发生的事情是persist()调用将用户的站点放在会话缓存中,而查询(无论它做什么)都会返回已经在缓存中的用户。
所以你有以下解决方案:
Hibernate.isInitialized()
测试查询是否加载了用户集合。请注意,调用retrievedUser.getSites().containsAll(sites)
将触发网站的延迟加载,因此不是测试查询急切地获取该集合的正确方法。Hibernate.isInitialized()
测试查询是否加载了用户集合。