2010-11-16 33 views
2

我有一个类似博客的情况下,有两个Java类:邮政和标签,这是一个@ManyToMany关系,具有Post_Tag关联表,这里是我的简单的定义:@ManyToMany不一致的数据

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>(); 
} 

似乎确定,但在下面的测试场景失败:

  1. 创建一个标签,标签1
  2. 创造第一位后,POST1
  3. 创建第二个帖子,POST2
  4. 外接TAG1到post1.getTags()和post2.getTags()
  5. 更新POST1,POST2
  6. 列表列表= dao.getPostByTag(TAG1)
  7. 断言则为list.size()== 2 ,失败

这里是我的测试代码:

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),休眠-3.5.6,JPA 2.0

回答

1

您可以在每次调用测试方法时执行的测试类中创建两个方法。这些方法将打开事务和之后做回滚:

@Before public void setUp() throws Exception { 
    em.getTransaction().begin(); 
} 

@After public void tearDown() throws Exception {  
     em.getTransaction().rollback(); 
} 

您也应该检查,如果你有从deffault不同flushmode因为通常flushs在查询之前做...

1

有两件事情可以尝试:

  1. 呼叫session.flush()上的两个更新来电之后你的Hibernate的Session,调用getPostsByTag前()。这应该将更改推送到数据库。
  2. 修复您的对象管理。当你有双面关联时,hibernate希望你能正确地维护关联的双方。

因此:

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); 

这是创建该管理协会两侧的一次方法是个好主意。

+0

您好,我尝试了第二种方式,仔细管理关联的两端,但dao.getPostsByTag()仍然在hibernate插入关联表之前执行。我尝试在dao.getPostsByTag()之前插入tagDao.update(tag1),但仍然是相同的错误答案(空列表)。 – smallufo 2010-11-16 04:45:27

+0

你尝试过调用session.flush()吗? – RMorrisey 2010-11-16 05:17:50

+0

嗨,我有问题调用session.flush(),因为它是一个测试类,这是超出休眠范围。这些DAO(postDao,tagDao)被注入到类中(在spring中)。测试类不知道底层的实现。是的,可能有某种方法可以从threadLocal或其他东西中获取当前绑定的会话,但我认为这不是在测试类中“刷新会话”的正常方法。应该有一些方法让hibernate'知道'它应该在更新关联表后执行getPostsByTag(),不是吗? – smallufo 2010-11-16 05:49:07