j'ai un scénario blog semblable, avec deux classes Java: Post et Tag, qui est une relation @ManyToMany, avec une table d'association Post_Tag, voici mes définitions simplifiées:données incohérentes de @ManyToMany sur les deux problèmes de côté
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>();
}
il semble OK, mais il échoue dans le scénario de test suivant:
- Créer une marque, balise1
- Créer 1er post, post1
- Créer 2ème message , Post2
- add balise1 à post1.getTags() et() post2.getTags
- mise à jour post1, post2
- Liste list = dao.getPostByTag (balise1)
- assert list.size() == 2 , ECHEC
Voici mon code de test:
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));
}
Et voici mon dao.getPostsByTag() la mise en œuvre de:
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();
}
La taille de la liste renvoyée == 0! J'ai remarqué la commande SQL générée et trouvé hibernate getPostsByTag() d'abord, puis insérer dans la table d'association, ce qui rend la getPostsByTag() retourner la liste de longueur 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
(?, ?)
Comment puis-je faire que le getPostsByTag() est exécutée after
l'insertion de la table d'association?
Je sais qu'il y avait des méthodes 'endTransaction(), et startNewTransaction()' dans spring-JUnit3, mais ne semble pas disponible dans spring-with-junit4.
Mais je me demande comment puis-je passer ce test dans one
transaction? Merci.
environnements: Spring4 (SpringJUnit4ClassRunner), mise en veille prolongée-3.5.6, JPA 2.0
Salut, je essayé la 2ème manière, en gérant soigneusement les deux côtés de l'association, mais dao.getPostsByTag() est toujours exécuté avant l'hibernation en insérant la table d'association. J'ai essayé d'insérer tagDao.update (tag1) avant dao.getPostsByTag(), mais toujours la même mauvaise réponse (liste vide). – smallufo
Avez-vous essayé d'appeler session.flush()? – RMorrisey
Bonjour, J'ai un problème pour appeler session.flush(), car il s'agit d'une classe de test, qui est en dehors de la portée d'hibernate. Ces DAO (postDao, tagDao) sont injectés dans la classe (au printemps). La classe de test ne connaît pas les implémentations sous-jacentes. Oui, il existe peut-être un moyen d'obtenir la session actuellement liée à threadLocal ou quelque chose, mais je pense que ce n'est pas une façon normale de «vider session» dans la classe de test. Il devrait y avoir un moyen pour que hibernate sache qu'il devrait exécuter getPostsByTag() après la mise à jour de la table d'association, n'est-ce pas? – smallufo