Hibernate ManyToMany和Restrictions.in

时间:2015-06-28 22:45:07

标签: hibernate many-to-many criteria hibernate-mapping hibernate-criteria

我有ArticleTag个实体:

@Entity
@Table(name = "articles")
public class Article implements Serializable{
   //other things

   @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
   private List<Tag> tags;
}

@Entity
@Table(name = "tags")
public class Tag implements Serializable{
    //other things

    @ManyToMany(mappedBy="tags" ,cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private List<Article> articles;
}

这个想法是:当第一个Articlefirst标签时,我有3 second秒。 第二个包含secondthird个标记。 第二个包含firstthird个标记。当我按Article标记过滤first时,我得到两个Article - 因为第一个和第三个Article被标记为first标记。当我按Article代码和second过滤third时,我得到了所有3 Article s - 因为每个Article都标记了其中一个Article。通常,目标是按指定的Tag之一过滤@Test public void test_WhenTagIdsAreSpecified_ArticlesShouldBeFilteredByOneOfTags() throws Exception { AuthorDTO author = getExpectedAuthor(); List<TagDTO> tags = saveThreeTags(); TagDTO firstTag = tags.get(0); TagDTO secondTag = tags.get(1); TagDTO thirdTag = tags.get(2); service.save(new ArticleDTO(null, author, Arrays.asList(firstTag, secondTag), articleContent + "_firstAndSecondTag")); service.save(new ArticleDTO(null, author, Arrays.asList(secondTag, thirdTag), articleContent + "_secondAndThirdTag")); service.save(new ArticleDTO(null, author, Arrays.asList(firstTag, thirdTag), articleContent + "_firstAndThirdTag")); assertEquals(3, tagService.getAll().size()); Collection<Long> tagIdsContainingFirst = Collections.singletonList(firstTag.getId()); List<ArticleDTO> articlesByFirstTag = service.getByTags(tagIdsContainingFirst); Collection<Long> tagIdsContainingSecondOrThirdTag = Arrays.asList(secondTag.getId(), thirdTag.getId()); List<ArticleDTO> articlesBySecondOrThirdTag = service.getByTags(tagIdsContainingSecondOrThirdTag); assertEquals(2, articlesByFirstTag.size()); assertEquals(articleContent + "_firstAndSecondTag", articlesByFirstTag.get(0).getContent()); assertEquals(articleContent + "_firstAndThirdTag", articlesByFirstTag.get(1).getContent()); assertEquals(3, articlesBySecondOrThirdTag.size()); //it fails } 。我写了一个单元测试,显示了我想要实现的目标:

Article

但不是3,我得到了4 Article s,这非常奇怪,因为我在数据库中只有3个。这就是我尝试过滤@Override public List<Article> getByTags(Collection<Long> tagIds) { return (List<Article>)createCriteria() .createAlias("tags", "t") .add(Restrictions.in("t.id", tagIds)) .list(); } 的方法:

second

第二个代码会被计算两次(我认为因为它有third Tag代码。它似乎在每个second“循环”,然后检查它是否在(thirdArticle)中然后如果它是真的添加{{1与Tag相关的。我还尝试分别为每个标记ID添加Restrinction.in

criteria.createAlias("tags", "t");
for (Long tagId: tagIds) {
    criteria.add(Restrictions.in("t.id", Collections.singleton(tagIds)));
}

但结果是0,没有预期的3 - IMO也因为它没有分别查看所有Tag,每个Tag上的机器人。有没有想法如何“一次查看所有标签”(如果你知道我的意思)?当我想用普通语言实现类似的东西时,它会有点像(类似Java的伪代码):

for (Article article: articles){
    List<Tag> tags = article.getTags();
    // As many conditions as tags to filter specified
    if ( tags.contains(second) || tags.contains(third) ... ) {
        filteredArticles.add(article);
    }
}

有人可以帮我解决这个问题吗?提前感谢您的每一个答案。

1 个答案:

答案 0 :(得分:1)

我自己找到了一个解决方案:

@Override
public List<Article> getByTags(Collection<Long> tagIds) {
    return (List<Article>)createCriteria()
            .createAlias("tags", "t")
            .add(Restrictions.in("t.id", tagIds))
            .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
            .list();
}

.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)失踪了。