休眠 ManyToMany 和 Restrictions.in
Hibernate ManyToMany and Restrictions.in
我有 Article
和 Tag
个实体:
@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;
}
想法是:当 First 有 first
和 second
标签时,我有 3 Article
s。 第二个 有second
和third
标签。 第二个 有first
和third
标签。当我通过 first
标签过滤 Article
s 时,我得到两个 Article
s - 因为第一个和第三个 Article
s 被标记为 first
标签。当我通过 second
标签和 third
过滤 Article
时,我得到了所有 3 个 Article
——因为每个 Article
都被其中之一标记。通常,目标是通过指定的 Tag
之一过滤 Article
。我写了一个单元测试,它显示了我想要实现的目标:
@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 个 Article
而不是 3 个,这很奇怪,因为我在数据库中只有 3 个。这就是我尝试过滤 Article
s:
的方式
@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
中都是 "loops",然后检查它是否在 (second
, third
) 中,然后检查它是否在true 添加与 Tag
相关的 Article
。我还尝试分别为每个标签 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
。有什么想法如何 "look on all tags at once" (如果你明白我的意思)?当我想用普通语言实现类似的东西时,它会有点像 (Java-like 伪代码):
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);
}
}
谁能帮我解决这个问题?预先感谢您的每一个回答。
我自己找到了解决方案:
@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)
丢失。
我有 Article
和 Tag
个实体:
@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;
}
想法是:当 First 有 first
和 second
标签时,我有 3 Article
s。 第二个 有second
和third
标签。 第二个 有first
和third
标签。当我通过 first
标签过滤 Article
s 时,我得到两个 Article
s - 因为第一个和第三个 Article
s 被标记为 first
标签。当我通过 second
标签和 third
过滤 Article
时,我得到了所有 3 个 Article
——因为每个 Article
都被其中之一标记。通常,目标是通过指定的 Tag
之一过滤 Article
。我写了一个单元测试,它显示了我想要实现的目标:
@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 个 Article
而不是 3 个,这很奇怪,因为我在数据库中只有 3 个。这就是我尝试过滤 Article
s:
@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
中都是 "loops",然后检查它是否在 (second
, third
) 中,然后检查它是否在true 添加与 Tag
相关的 Article
。我还尝试分别为每个标签 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
。有什么想法如何 "look on all tags at once" (如果你明白我的意思)?当我想用普通语言实现类似的东西时,它会有点像 (Java-like 伪代码):
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);
}
}
谁能帮我解决这个问题?预先感谢您的每一个回答。
我自己找到了解决方案:
@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)
丢失。