我有一个类似博客的场景,有两个Java类:Post和Tag,这是一个@ManyToMany关系,带有Post_Tag关联表,这是我的简化定义:
public class Post
{
@ManyToMany(fetch=FetchType.LAZY)
@Fetch(FetchMode.SELECT)
@JoinTable(name = "Post_Tag"
, joinColumns = @JoinColumn(name="Post_id")
, inverseJoinColumns = @JoinColumn(name="Tag_id")
)
private Set<PostTag> tags = new HashSet<PostTag>();
}
public class Tag
{
@ManyToMany(mappedBy="tags" , fetch=FetchType.LAZY)
private Set<Post> comments = new HashSet<Post>();
}
看起来没问题,但在以下测试场景中失败了:
这是我的测试代码:
public void testGetCommentsByTag()
{
Tag tag1 = tagDao.save(new Tag("tag1"));
assertTrue(tag1.getId() > 0);
Post post1 = dao.save("...");
Post post2 = dao.save("...");
post1.getTags().add(tag1);
post2.getTags().add(tag1);
dao.update(post1);
dao.update(post2);
List<Post> list = dao.getPostsByTag(tag1 , 0 , 100);
assertSame(2 , list.size()); // FAILED !
assertTrue(list.contains(post1));
assertTrue(list.contains(post2));
}
这是我的dao.getPostsByTag()的实现:
public List<Post> getPostsByTag(Tag tag , int start, int count)
{
Session session = (Session) em.getDelegate();
Criteria c = session.createCriteria(Post.class);
c.createCriteria("tags")
.add(Restrictions.eq("id", tag.getId()));
c.setFirstResult(start);
c.setMaxResults(count);
c.setCacheable(true);
return c.list();
}
返回的列表大小== 0! 我注意到生成的SQL命令并首先找到了hibernate getPostsByTag()然后插入到关联表中,这使得getPostsByTag()返回0长度列表。 :
Hibernate:
insert
into
Tag
values
(?, ?, ?, ?)
Hibernate:
insert
into
Post
(...)
values
(???)
Hibernate:
insert
into
Post
(...)
values
(???)
Hibernate:
select
ooxx
from
Post this_
inner join
Post_Tag tags3_
on this_.id=tags3_.Post_id
inner join
Tag tag1_
on tags3_.Tag_id=tag1_.id
where
and tag1_.id=?
order by
this_.created desc limit ?
Hibernate:
insert
into
Post_Tag
(Post_id, Tag_id)
values
(?, ?)
Hibernate:
insert
into
Post_Tag
(Post_id, Tag_id)
values
(?, ?)
如何确保插入关联表时执行getPostsByTag()after
?
我知道spring-JUnit3中有'endTransaction()和startNewTransaction()'方法,但是在spring-with-junit4中似乎没有。
但我想知道如何在one
交易中通过此测试?
感谢。
环境:Spring4(SpringJUnit4ClassRunner),hibernate-3.5.6,JPA 2.0
答案 0 :(得分:1)
你可以尝试两件事:
session.flush()
。这应该将您的更改推送到数据库。因此:
Tag tag1 = tagDao.save(new Tag("tag1"));
assertTrue(tag1.getId() > 0);
Post post1 = dao.save("...");
Post post2 = dao.save("...");
post1.getTags().add(tag1);
tag1.getPosts().add(post1);
post2.getTags().add(tag1);
tag1.getPosts().add(tag2);
dao.update(post1);
dao.update(post2);
创建一次管理关联双方的方法是个好主意。
答案 1 :(得分:1)
您可以在测试类中创建两个方法,每次调用测试方法时都会执行这两个方法。这些方法将打开事务并在其后执行回滚:
@Before public void setUp() throws Exception {
em.getTransaction().begin();
}
@After public void tearDown() throws Exception {
em.getTransaction().rollback();
}
你应该检查你是否有一个与deffault不同的flushmode,因为通常在查询之前进行刷新...