问题描述
我有一个类似博客的场景,有两个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>();
$ b $ public class Tag
{
@ManyToMany(mappedBy =tags,fetch = FetchType.LAZY)
private Set< Post> comments = new HashSet< Post>();
}
看起来不错,但在以下测试场景中失败:
- 创建标签tag1
- 创建第一篇文章,post1
- 创建第二个帖子,post2
- 添加tag1到post1.getTags()和post2.getTags()
- 更新post1,post2
- 列表列表= dao.getPostByTag(tag1)
- assert list.size()== 2,FAILED
这是我的测试代码:
public void testGetCommentsByTag()
{
Tag tag1 = tagDao.save(new Tag(tag1));
assertTrue(tag1.getId()> 0);
发布post1 = dao.save(...);
发布post2 = dao.save(...);
post1.getTags()。add(tag1);
post2.getTags()。add(tag1);
dao.update(post1);
dao.update(post2);
列表< Post> list = dao.getPostsByTag(tag1,0,100);
assertSame(2,list.size()); //失败!
assertTrue(list.contains(post1));
assertTrue(list.contains(post2));
$ / code>
这里是我的dao.getPostsByTag()的实现:
public List< Post> getPostsByTag(标记标记,int start,int count)
{
Session session =(Session)em.getDelegate();
标准c = session.createCriteria(Post.class);
c.createCriteria(tags)
.add(Restrictions.eq(id,tag.getId()));
c.setFirstResult(start);
c.setMaxResults(count);
c.setCacheable(true);
返回c.list();
}
返回的列表大小== 0!
我注意到了生成的SQL命令,发现hibernate先getPostsByTag(),然后插入关联表,这会使getPostsByTag()返回0长度列表。 :
Hibernate:
插入
到
标签
值
(?,?,?,?)
Hibernate:
将
插入
后
(...)
)
Hibernate:
将
插入
后
(...)
值
(???)
Hibernate:
选择
ooxx
from
发布this_
内部连接
Post_Tag tags3_
on this_.id = tags3_.Post_id
内连接
标签tag1_
位于tags3_.Tag_id = tag1_.id
其中
和tag1_.id =?
order by
this_.created desc limit?
Hibernate:
将
插入
Post_Tag
(Post_id,Tag_id)
值
(?,?)
Hibernate:
将
插入
Post_Tag
(Post_id,Tag_id)
值
(?,?)
$ b如何确保getPostsByTag()在插入关联表后执行 ?
我知道spring-JUnit3中有'endTransaction()和startNewTransaction()'方法,但在spring-with-junit4中似乎不可用。
但我不知道如何在一个交易中通过这个测试?
Thanks。
环境:Spring4(SpringJUnit4ClassRunner),hibernate-3.5.6,JPA 2.0
解决方案您可以在每次调用测试方法时执行的测试类中创建两个方法。这些方法将打开事务并在它之后进行回滚:
@Before public void setUp()throws Exception {
em.getTransaction()()开始。
}
@ public void tearDown()抛出异常{
em.getTransaction()。rollback();
}
您应该检查是否有与deffault不同的flushmode,因为通常刷新之前进行查询...
I have a blog-like scenario , with two Java classes : Post and Tag , which is a @ManyToMany relationship , with a Post_Tag association table , here is my simplified definitions:
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>(); }It seems OK , but it fails in the following testing scenario :
- Create a Tag , tag1
- Create 1st Post , post1
- Create 2nd Post , post2
- add tag1 to post1.getTags() and post2.getTags()
- update post1 , post2
- List list = dao.getPostByTag(tag1)
- assert list.size() == 2 , FAILED
Here is my test code :
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)); }And here is my dao.getPostsByTag()'s implementation :
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(); }The returned list size == 0 !I noticed the generated SQL command and found hibernate first getPostsByTag() and then insert to association table , which makes the getPostsByTag() return 0-length list. :
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 (?, ?)How do I make sure the getPostsByTag() is executed after inserting the association table ?
I know there was 'endTransaction() , and startNewTransaction()' methods in spring-JUnit3 , but seems not available in spring-with-junit4.
But I wonder how can I pass this test in one transaction ?Thanks.
environments : Spring4 (SpringJUnit4ClassRunner) , hibernate-3.5.6 , JPA 2.0
解决方案You can create two methods in the test class that will be executed each time a test method is called. These methods will open the transaction and do rollback after it:
@Before public void setUp() throws Exception { em.getTransaction().begin(); } @After public void tearDown() throws Exception { em.getTransaction().rollback(); }You should check also if you have a flushmode different from the deffault because normally the flushs are made before a query...
这篇关于@ManyToMany双方的数据不一致的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!