我有一个包含M:N元素集合(标签)的对象(BlogPost)。
如何查询一个对象(BlogPost),其中至少有一个对象与一组标签(由用户定义)中的元素与JPA2(Hibernate)匹配。
findBlogPostWithAtLeastOneMatchingTag(Collection<Tag> tags){ ???? }
我的主要问题是,我实际上需要比较两个标签集合: - BlogPost的标签集合。 - 我搜索的集合
我尝试Select p from Post p where p.tags in(:tags)
但它不起作用,因为我的帖子实体只有一个标签。
那我该怎么做呢?
我的BlogPost实体看起来像这样。它有几个标签。
@Entity
public class BlogPost{
/** The tags. */
@ManyToMany()
@NotNull
private Set<Tag> tags;
@NotBlank
private String content;
...
}
解决方案不能是JPQL,JPA-Criteria(不是Hibernate-Criteria)也不错。
答案 0 :(得分:7)
如果你喜欢JPA Criteria,这就是你的解决方案:
List<Integer> myTagsIds = new ArrayList<Integer> ();
myTagsIds.add(1);
myTagsIds.add(2);
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<BlogPost> cq = cb.createQuery(BlogPost.class);
Root<BlogPost> blogPost = cq.from(BlogPost.class);
SetJoin<BlogPost, Tag> tags = blogPost.join(BlogPost_.tags);
Predicate predicate = tags.get(Tag_.id).in(myTagsIds);
cq.distinct(true);
cq.where(predicate);
TypedQuery<BlogPost> tq = em.createQuery(cq);
return tq.getResultList();
此解决方案使用了应由JPA实现生成的canonical MetaModel类BlogPost_
和Tag_
。
答案 1 :(得分:2)
在SQL中它可能是这样的:
SELECT p FROM Post p WHERE (p.tags INTERSECT :tags IS NOT EMPTY);
然后应用@SqlResultSetMapping
。
您可以使用Criteria API
并按照您的操作开始,但是在Collection<Tag> tags
上进行循环:
* make a union of single query results from `Select p from Post p where p.tags in(:tags)`;
* take distinct over result of union.
查询将是服务器端的,您不必在Java中进行脏工作。
答案 2 :(得分:1)
您可以执行类似
的操作从帖子t中选择t,其中t.tag in(从post p中选择p.tag,其中p.id =:id)
id是当前帖子的ID。基本上,您选择的帖子中包含当前帖子标签中的标签。