我使用以下技术:
我通过集成测试测试了一些具有功能的代码,我需要检查实体是否正确保存/更新/删除或任何其他更改。我的 .xml 中有 sessionFactory 配置:
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"
p:dataSource-ref="dataSource" p:hibernateProperties="jdbcProperties">
<property name="packagesToScan" value="my.package"/>
</bean>
和测试类示例:
@ContextConfiguration(locations = {"classpath:/applicationContext-test.xml",
"classpath:/applicationContext-dao.xml",
"classpath:/applicationContext-orm.xml"})
public class AccountServiceTest extends AbstractTransactionalTestNGSpringContextTests {
@Autowired
private SomeService someService;
@Autowired
private SessionFactory sessionFactory;
@Test
public void updateEntity() {
//given
Long entityId = 1L;
SomeClass expected = someService.get(entityId);
String newPropertyValue = "new value";
//when
someService.changeEntity(entity, newPropertyValue);
// Manual flush is required to avoid false positive in test
sessionFactory.getCurrentSession().flush();
//then
expected = someService.get(entityId);
Assert.assertEquals(expected.getChangedProperty() , newPropertyValue);
}
服务方式:
@Transactional
@Override
public int changeEntity(entity, newPropertyValue) {
return dao().executeNamedQuery(REFRESH_ACCESS_TIME_QUERY,
CollectionUtils.arrayToMap("id", entity.getId(), "myColumn", newPropertyValue));
}
DAO:
@Override
public int executeNamedQuery(final String query, final Map<String, Object> parameters) {
Query queryObject = sessionFactory.getCurrentSession().getNamedQuery(query);
if (parameters != null) {
for (Map.Entry<String, Object> entry : parameters.entrySet()) {
NamedQueryUtils.applyNamedParameterToQuery(queryObject, entry.getKey(), entry.getValue());
}
}
return queryObject.executeUpdate();
}
但是我的实体属性在flush()
之后没有改变如此处所述change @Autowire SessionFactory with @PersistenceContext EntityManager ,我应该EntityManager
使用flush()
- 但我不能这样做 - 我无法将sessionFactory
转换为{{1}我不需要为我的应用程序创建EntityManager
- 因为我需要更改 .xml 配置文件和其他文件。
这个问题还有其他解决办法吗?
答案 0 :(得分:0)
您的代码实际上正在按预期工作。
您的测试方法是事务性的,因此在整个测试方法执行期间Session
仍然存在。 Session
也是hibernate的第一级缓存,当从数据库加载实体时,它被放入会话中。
因此,行SomeClass expected = someService.get(entityId);
将从数据库加载实体,并将其放入Session
。
现在这行expected = someService.get(entityId);
首先检查(实际上是下面的dao方法)检查具有id的请求类型的实体是否已经存在于Session
中,如果是这样,它只是返回它。它将不查询数据库!。
主要问题是你以错误的方式使用hibernate,你基本上是以更新数据库的方式绕过hibernate。您应该更新您的实体并坚持下去。您不应该编写查询来更新数据库!
带注释的测试方法
@Test
public void updateEntity() {
//given
Long entityId = 1L;
SomeClass expected = someService.get(entityId); // load from db and put in Sesion
String newPropertyValue = "new value";
//when
someService.changeEntity(entity, newPropertyValue); // update directly in database bypass Session and entity
// Manual flush is required to avoid false positive in test
sessionFactory.getCurrentSession().flush();
//then
expected = someService.get(entityId); // return entity from Session
Assert.assertEquals(expected.getChangedProperty() , newPropertyValue);
}
要仅修复测试,请在clear()
之后添加对flush()
的调用。
sessionFactory.getCurrentSession().clear();
然而,您实际应该做的是停止编写这样的代码并以正确的方式使用Hibernate和持久实体。
@Test
public void updateEntity() {
//given
Long entityId = 1L;
String newPropertyValue = "new value";
SomeClass expected = someService.get(entityId);
expected.setMyColumn(newPropertyValue);
//when
someService.changeEntity(entity);
sessionFactory.getCurrentSession().flush();
// now you should use a SQL query to verify the state in the DB.
Map<String, Object> dbValues = getJdbcTemplate().queryForMap("select * from someClass where id=?", entityId);
//then
Assert.assertEquals(dbValues.get("myColumn"), newPropertyValue);
}
你的dao方法应该是这样的。
public void changeEntity(SomeClass entity) {
sessionFactory.getCurrentSession().saveOrUpdate(entity);
}