本文介绍了@ManyToMany双方的数据不一致的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类似博客的场景,有两个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>();
}

看起来不错,但在以下测试场景中失败:


  1. 创建标签tag1

  2. 创建第一篇文章,post1

  3. 创建第二个帖子,post2

  4. 添加tag1到post1.getTags()和post2.getTags()

  5. 更新post1,post2

  6. 列表列表= dao.getPostByTag(tag1)

  7. 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 :

  1. Create a Tag , tag1
  2. Create 1st Post , post1
  3. Create 2nd Post , post2
  4. add tag1 to post1.getTags() and post2.getTags()
  5. update post1 , post2
  6. List list = dao.getPostByTag(tag1)
  7. 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双方的数据不一致的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 01:55