【问题标题】:Hibernate ManyToMany and Restrictions.in休眠多对多和 Restrictions.in
【发布时间】:2015-09-15 07:36:51
【问题描述】:

我有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;
}

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

@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
}

但是我得到了 4 个 Articles 而不是 3 个,这很奇怪,因为我在数据库中只有 3 个。这就是我尝试过滤Articles的方式:

@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, third) 中,然后如果是真的添加与 Article 相关的 Tag。我还尝试为每个标签 ID 分别添加 Restrinction.in

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

但结果是 0,没有预期的 3 - IMO 也是因为它不会单独查看所有 Tags,每个 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);
    }
}

谁能帮我解决这个问题?提前感谢您的每一个回答。

【问题讨论】:

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


    【解决方案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) 不见了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-09-30
      • 2021-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-22
      相关资源
      最近更新 更多