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);
我遇到了一个我想不出解决办法的问题。 所以我得到了这段代码:
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);