首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Hibernate ManyToMany和Restrictions.in

Hibernate ManyToMany和Restrictions.in
EN

Stack Overflow用户
提问于 2015-06-28 22:45:06
回答 1查看 411关注 0票数 0

我有ArticleTag实体:

代码语言:javascript
复制
@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;
}

我的想法是:我有3个Article,当Firstfirstsecond标记时。第二代secondthird标记。第二代firstthird标记。当我通过Article标记过滤first s时,我得到了两个Articles --因为第一个和第三个Articles被标记为first标记。当我用second标记和third过滤seconds时,我得到了所有的3个Articles --因为每个Article都有一个标记。通常,目标是通过指定的Article之一过滤Tag。我编写了一个单元测试,它显示了我想要实现的目标:

代码语言:javascript
复制
@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
}

但我得到的不是3,而是4Article,这很奇怪,因为数据库中只有3。这就是我如何过滤Articles的方法:

代码语言:javascript
复制
@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中都是“循环”的,然后检查它是否在(secondthird),然后检查它是否是与Tag相关的真正的add Article。我还尝试为每个标记ID分别添加Restrinction.in

代码语言:javascript
复制
criteria.createAlias("tags", "t");
for (Long tagId: tagIds) {
    criteria.add(Restrictions.in("t.id", Collections.singleton(tagIds)));
}

但结果是0,没有预期的3-IMO也因为它没有看到所有的Tag,bot分别在每个Tag上。你知道如何“同时查看所有标签”(如果你知道我的意思)吗?当我想在普通语言中实现类似的目标时,它会有点像(类似Java的伪代码):

代码语言:javascript
复制
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);
    }
}

有人能帮我解决这个问题吗?谢谢您的每一个答复。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-06-29 21:01:48

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

代码语言:javascript
复制
@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)失踪了。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31105530

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档