微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么“ ORDER BY field_name LIKE'start%'”在普通SQL中不能在Hibernate / Spring / JPA中使用?

如何解决为什么“ ORDER BY field_name LIKE'start%'”在普通SQL中不能在Hibernate / Spring / JPA中使用?

问题:

我有一个需要在ORDER BY语句中使用LIKE的查询。 尽管这在普通sql中有效,但我无法使其在JPQLCriteriaQuery中工作; 因此,问题始终出在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("..")JPQLCriteriaQuery结合使用,以保持数据库独立性。

@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 举报,一经查实,本站将立刻删除。