2010-11-16 63 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