HQL Hibernate 查询搜索检查列表是否包含另一个列表的所有元素

HQL Hibernate query search check if list contains all elements of another list

我遇到了一个我想不出解决办法的问题。 所以我得到了这段代码:

public List<Post> getPosts(List<PostStrategy> allowedStrategyList, Set<Tag> allowedTags, int page, int resultsPerPage) {
    return entityManager.createQuery("select post from Post post join post.tags tag where post.postStrategy in (:postStrategyList) and (:allowedTagsSize = 0 or tag in (:allowedTags))", Post.class)
            .setParameter("postStrategyList", allowedStrategyList)
            .setParameter("allowedTags", allowedTags)
            .setParameter("allowedTagsSize", allowedTags.size())
            .setFirstResult((page - 1) * resultsPerPage)
            .setMaxResults(resultsPerPage)
            .getResultList();
}

这段代码的问题在于,当有人使用多个标签(例如:#video、#image)进行搜索时,它 return 都 post 使用两个标签和一个标签。

我希望它成为 return 一个 post,同时在其标签中包含 #video 和 #image。为了让它工作,我需要以某种方式检查列表是否包含另一个列表的所有元素。

我搜索了一段时间的解决方案并尝试了不同的方法,到目前为止没有。

我尝试将 "tag in (:allowedTags)" 替换为 "post.tags in (:allowedTags)",但我的 SQL 无效。

两年后我得到了答案。我现在正在使用 Spring Boot 和 SpEL 表达式,请耐心等待。这个查询比我最初的想法多了一点,但你可以从中提取你需要的东西。

@Override
@Query("select p from PostSnapshot p where " +
        // Tags
        "(:#{#query.withTags.size()} = 0 or p.id in (" +
        "select post.id from PostSnapshot post inner join post.tags tag " +
        "where tag.value in (:#{#query.withTags}) " +
        "group by post.id " +
        "having count(distinct tag.value) = :#{#query.withTags.size() * 1L}" +
        ")) and (:#{#query.withoutTags.size()} = 0 or p.id not in (" +
        "select post.id from PostSnapshot post inner join post.tags tag " +
        "where tag.value in (:#{#query.withoutTags}) " +
        "group by post.id " +
        "having count(distinct tag.value) = :#{#query.withoutTags.size() * 1L}" +
        ")) " +
        // Artists
        "and (:#{#query.withArtists.size()} = 0 or p.id in (" +
        "select post.id from PostSnapshot post inner join post.artists artist " +
        "where artist.preferredNickname in (:#{#query.withArtists}) " +
        "group by post.id " +
        "having count(distinct artist.preferredNickname) = :#{#query.withArtists.size() * 1L}" +
        ")) and (:#{#query.withoutArtists.size()} = 0 or p.id not in (" +
        "select post.id from PostSnapshot post inner join post.artists artist " +
        "where artist.preferredNickname in (:#{#query.withoutArtists}) " +
        "group by post.id " +
        "having count(distinct artist.preferredNickname) = :#{#query.withoutArtists.size() * 1L}" +
        ")) " +
        // Title like words
        "and lower(p.title) like concat('%', lower(:#{(#query.words.isEmpty()) ? '' : #query.words.toArray()[0]}) ,'%')" +
        // OwnerId
        "and p.ownerId = :ownerId")
Page<PostSnapshot> findAllByOwnerIdAndQuery(@Param("ownerId") UUID ownerId, @Param("query") PostQuerySearchDTO query, Pageable pageable);