如何解决为什么“ ORDER BY field_name LIKE'start%'”在普通SQL中不能在Hibernate / Spring / JPA中使用?
问题:
我有一个需要在ORDER BY语句中使用LIKE的查询。
尽管这在普通sql中有效,但我无法使其在JPQL
或CriteriaQuery
中工作;
因此,问题始终出在order by LOWER(i.name) like "abc%" desc
上!
此查询有效,并列出名称中包含搜索词的项目。它首先返回名称以搜索词开头的项目,然后返回所有其他项目。这是普通sql中的查询:
SELECT i.name,i.popularity
FROM item i
left join picture p on p.id=i.picture_id and p.disabled=false
left join picture b on p.id=i.background_picture_id and b.disabled=false
WHERE i.disabled=false and LOWER(i.name) like "%abc%"
order by LOWER(i.name) like "abc%" desc,i.popularity desc
limit 50;
虽然这是一个开始,但我希望将JpaRepository
与@Query("..")
,JPQL
或CriteriaQuery
结合使用,以保持数据库独立性。
@Query("SELECT i FROM ItemEntity i " +
"left join i.picture p on p.disabled=false " +
"left join i.backgroundPicture b on b.disabled=false " +
"WHERE i.disabled=false and LOWER(i.name) like %:partialName% " +
"order by (LOWER(i.name) like :partialNameOrderBy%) desc,i.popularity desc")
Page<ItemListView> findActiveItemsWhereNameContains(@Param("partialName") String partialNameLowerCase,@Param("partialNameOrderBy") String partialNameLowerCaSEOrderByStartsWith,Pageable pageable);
此JPQL查询结果:
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected AST node: like near line 1,column
所以我以CriteriaQuery
的身份尝试过:
@Override
public Page<ItemListView> findActiveItemsWhereNameContains(String partialName,int maxResults) {
String partialNameLowerCase = StringUtils.lowerCase(StringUtils.trimToEmpty(partialName));
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<ItemListView> cq = cb.createquery(ItemListView.class);
Root<ItemEntity> item = cq.from(ItemEntity.class);
Join<ItemEntity,Ct2PictureEntity> picture = item.join(ItemEntity_.picture,JoinType.LEFT);
picture.on(cb.and(picture.geton()),cb.isFalse(picture.get(Ct2PictureEntity_.disabled)));
Join<ItemEntity,Ct2PictureEntity> backgroundPicture = item.join(ItemEntity_.backgroundPicture,JoinType.LEFT);
picture.on(cb.and(backgroundPicture.geton()),cb.isFalse(backgroundPicture.get(Ct2PictureEntity_.disabled)));
Predicate itemIsActive = cb.isFalse(item.get(ItemEntity_.disabled));
Predicate itemNameContainsSearch = cb.like(item.get(ItemEntity_.name),"%" + partialNameLowerCase + "%");
Predicate itemNameStartsWithSearch = cb.like(item.get(ItemEntity_.name),partialNameLowerCase + "%");
cq.select(cb.construct(
ItemListViewDto.class,item.get(ItemEntity_.id),item.get(ItemEntity_.name),item.get(ItemEntity_.popularity),CriteriaBuilderUtils.getMediumAndThumbnailPicture(cb,picture),CriteriaBuilderUtils.getMediumPicture(cb,backgroundPicture)))
.where(cb.and(itemIsActive,itemNameContainsSearch)).orderBy(cb.desc(itemNameStartsWithSearch),cb.desc(item.get(ItemEntity_.popularity)));
TypedQuery<ItemListView> query = entityManager.createquery(cq);
Pageable pageable = PageRequest.of(0,maxResults);
int totalRows = query.getResultList().size();
query.setFirstResult(pageable.getPageNumber() * pageable.getPageSize());
query.setMaxResults(pageable.getPageSize());
return new PageImpl<>(query.getResultList(),pageable,totalRows);
}
此查询结果:
org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected AST node: like near line 1,column
问题:
如何使用JPA或Hibernate编写此查询并避免使用本机sql?
解决方法
这里的问题是Hibernate不会强制谓词使用布尔表达式。您将不得不使用例如可以将CASE WHEN (LOWER(i.name) like :partialNameOrderBy%) THEN 1 ELSE 0 END
放入order by子句中。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。