我有经典的“多对多(帖子-PostTags-标签)”实体关系,具体如https://vladmihalcea.com/the-best-way-to-use-the-manytomany-annotation-with-jpa-and-hibernate/中所述。
我只有2个实体Posts和Tag,并且我使用@JoinTable表示PostTag,我没有有一个单独的实体类来表示PostTag。另外,我没有在“标签”实体中具有以下内容。我没有使用JPQL。
@ManyToMany(mappedBy = "tags")
private List<Post> posts = new ArrayList<>();
我有兴趣查找所有标有某些选定标签的帖子(包括所有内容,表示SQL为“ AND”条件)。最终用户可以自由选择1到4个标签。 (因此需要动态查询生成)。
我知道在SQL中这样做涉及联接表上的自联接。如何使用Criteria或HQL实现它?
我在SQL中尝试过,它涉及2个标签的联接表上的自联接。对3个或4个标签执行此操作将意味着有许多自连接:-(
select * from Posts where id in
(select distint pt1.post_id
from Post_Tag pt1 join Post_Tag pt2 on pt1.post_id = pt2.post_id
where pt1.tagId = 1 and pt2.tagId = 2)
我还尝试将Criteria用于Post.class,将DetachedCriteria用于Tag.class,但是由于我没有PostTags连接实体,因此无法有效地在类上设置投影。
如何使用Criteria或HQL实现它?正确地处理动态部分(1或2或3或4个标签)是我努力实现的目标。
仅显示上述问题的关注领域。为了简洁起见,省略休息。
@Entity(name = "Post")
@Table(name = "post")
public class Post {
@Id
@GeneratedValue
private Long id;
@ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
@JoinTable(name = "post_tag",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "tag_id")
)
Set List<Tag> tags = new ArrayList<>();
}
@Entity(name = "Tag")
@Table(name = "tag")
public class Tag {
@Id
@GeneratedValue
private Long id;
@NaturalId
private String name;
public Tag() {}
public Tag(String name) {
this.name = name;
}
public List<Posts> findByTags(List<String> tagNames) {
Criteria criteria = criteria(); // criteria for Post.class abstracted in the DAO
criteria.createAlias("tags", "tags");
Conjunction conjunction = Restrictions.conjunction();
tagNames.stream()
.forEach(t -> conjunction.add(Restrictions.eq("tags.name", t)));
criteria.add(conjunction);
return list(criteria);
}
当我只需要查询1个标签时,它就可以工作。但是当我查询1个以上的标签时给出0个结果,这是错误的。