简体   繁体   English

如何查询与JPA2的M:N关系?

[英]How to query an M:N relationship with JPA2?

I have an an object (BlogPost) that contains an M:N collection of elements (Tags). 我有一个对象(BlogPost),它包含一个M:N元素集合(标签)。

How to query for an object (BlogPost) where at least one it its Tags matches an element in a set of Tags (defined by the user) with JPA2 (Hibernate). 如何查询一个对象(BlogPost),其中至少有一个对象的标签与一组标签(由用户定义)中的元素与JPA2(Hibernate)匹配。

findBlogPostWithAtLeastOneMatchingTag(Collection<Tag> tags){ ???? }

My main problem is, that I actually need to compare two collections of tags: - the collection of tags of the BlogPost. 我的主要问题是,我实际上需要比较两个标签集合: - BlogPost的标签集合。 - the collection I search for - 我搜索的集合

I tried Select p from Post p where p.tags in(:tags) but it does not work, as my post entities have more than just one tag. 我尝试Select p from Post p where p.tags in(:tags)但它不起作用,因为我的帖子实体只有一个标签。

So what could I do instead? 那我该怎么做呢?

My BlogPost entity looks like this. 我的BlogPost实体看起来像这样。 It has several Tags. 它有几个标签。

@Entity
public class BlogPost{

    /** The tags. */
    @ManyToMany()
    @NotNull
    private Set<Tag> tags;

    @NotBlank
    private String content;

    ...
}

The solution must not be JPQL, JPA-Criteria (not Hibernate-Criteria) would be fine too. 解决方案不能是JPQL,JPA-Criteria(不是Hibernate-Criteria)也可以。

If you like JPA Criteria, this is the solution for you: 如果你喜欢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();

This solution makes use of the canonical MetaModel classes BlogPost_ and Tag_ that should be generated by your JPA implementation. 此解决方案使用应由JPA实现生成的规范MetaModelBlogPost_Tag_

Approach 1: 方法1:

In SQL it could be something like: 在SQL中它可能是这样的:

SELECT p FROM Post p WHERE (p.tags INTERSECT :tags IS NOT EMPTY);

Then apply the @SqlResultSetMapping . 然后应用@SqlResultSetMapping

Approach 2: 方法2:

You can use Criteria API and start as you did but make a loop over Collection<Tag> tags as: 您可以使用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.

Query will be server-side and you wouldn't have to do dirty work in Java. 查询将是服务器端,您不必在Java中进行脏工作。

You could do something like 你可以做点什么

Select t from Post t where t.tag in (select p.tag from Post p where p.id=:id) 从Post t中选择t,其中t.tag in(从post p中选择p.tag,其中p.id =:id)

id is the id of the current post. id是当前帖子的ID。 Basically you are selecting post with tags that are in the tags of current post. 基本上,您选择的帖子中包含当前帖子标签中的标签。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM