In back end (java spring boot) sorting, how to sort with Alias name using pageable? Without parent table as prefix

huangapple go评论86阅读模式
英文:

In back end (java spring boot) sorting, how to sort with Alias name using pageable? Without parent table as prefix

问题

我正在使用Java Spring Boot的pageable进行后端分页和排序。在将排序字段设为usercount(这会给出user_role_mapping的计数)时,Java会触发错误column f.usercount不存在
实际上,usercount不是一个列名,而是一个别名。

如何在排序时使用usercount作为别名,而不带上**f.**作为前缀?

API网址:

http://localhost:8080/facility/list?pageNumber=0&pageSize=10&sortBy=usercount&sortType=asc

控制器层默认的sortBysortType分别是iddesc

以下是Java代码:

Pageable pageable = PageRequest.of(pageNumber, pageSize, Sort.by(sortBy).descending());
if (sortType.equalsIgnoreCase("asc")) {
	pageable = PageRequest.of(pageNumber, pageSize, Sort.by(sortBy).ascending());
}
Page<FacilityProjection> facilityList = facilityRepository.facilityListing(12,pageable);

用于列出设施详细信息以及基于角色ID的用户计数的Postgres SQL Hibernate查询如下:

@Query(nativeQuery = true, value = " Select f.name as facilityname,f.id as facilityid,count(urm.id) as usercount 
 from facility f
 join user u on f.user_id=u.id 
 join user_role_mapping urm on u.id = urm.user_id 
 where urm.role_id=:roleId ")
Page<FacilityProjection> facilityListing(@Param("roleId") Long roleId,Pageable pageable);
英文:

I am using backend pagination and sorting with java spring boot pageable. While passing sort field as usercount (This gives count of user_role_mapping), Java triggering an error column f.usercount does not exist .
Actually usercount not a column it's an Alias name.

How to sort using usercount as Alies name without f. as prefix?

API URL:

http://localhost:8080/facility/list?pageNumber=0&pageSize=10&sortBy=usercount&sortType=asc

Default sortBy & sortType are id and desc respectively in controller layer.

Java Code give below:

Pageable pageable = PageRequest.of(pageNumber, pageSize, Sort.by(sortBy).descending());
if (sortType.equalsIgnoreCase("asc")) {
	pageable = PageRequest.of(pageNumber, pageSize, Sort.by(sortBy).ascending());
}
Page<FacilityProjection> facilityList = facilityRepository.facilityListing(12,pageable);

Postgres sql Hibernate query for listing facility details along with user count based on role id, given below:

@Query(nativeQuery = true, value = " Select f.name as facilityname,f.id as facilityid,count(urm.id) as usercount 
 from facility f
 join user u on f.user_id=u.id 
 join user_role_mapping urm on u.id = urm.user_id 
 where urm.role_id=:roleId ")
Page<FacilityProjection> facilityListing(@Param("roleId") Long roleId,Pageable pageable);

答案1

得分: 2

问题在于usercount是聚合函数的结果。为了按照此字段排序,查询必须包含order by count(urm.id),而不是order by usercount

在这种情况下,我建议您使用Collections::sort重新对页面内容进行排序:

boolean sortByUserCount = sortBy.equalsIgnoreCase("usercount");
boolean desc = sortType.equalsIgnoreCase("desc");

final Pageable pageable;

if (sortByUserCount) {
    pageable = PageRequest.of(pageNumber, pageSize);
} else {
    if (desc) {
        pageable = PageRequest.of(pageNumber, pageSize, Sort.by(sortBy).descending());
    } else {
        pageable = PageRequest.of(pageNumber, pageSize, Sort.by(sortBy).ascending());
    }
}

Page<FacilityProjection> facilityList = facilityRepository.facilityListing(12, pageable);

if (sortByUserCount) {
    Comparator<FacilityProjection> comparator = Comparator.comparing(FacilityProjection::getUserCount);

    if(desc) {
        comparator = comparator.reversed(); 
    }
    Collections.sort(facilityList.getContent(), comparator);
}
英文:

The problem is that usercount is aggregation function result. To order by this field query have to contain order by count(urm.id) instead of order by usercount.

In this case I'd suggest you to resort page content using Collections::sort

boolean sortByUserCount = sortBy.equalsIgnoreCase(&quot;usercount&quot;);
boolean desc = sortType.equalsIgnoreCase(&quot;desc&quot;);

final Pageable pageable;

if (sortByUserCount) {
    pageable = PageRequest.of(pageNumber, pageSize);
} else {
    if (desc) {
        pageable = PageRequest.of(pageNumber, pageSize, Sort.by(sortBy).descending());
    } else {
        pageable = PageRequest.of(pageNumber, pageSize, Sort.by(sortBy).ascending());
    }
}

Page&lt;FacilityProjection&gt; facilityList = facilityRepository.facilityListing(12, pageable);

if (sortByUserCount) {
    Comparator&lt;FacilityProjection&gt; comparator = Comparator.comparing(FacilityProjection::getUserCount);

    if(desc) {
        comparator = comparator.reversed(); 
    }
    Collections.sort(facilityList.getContent(), comparator);
}

答案2

得分: 1

据我所知,这是不可能的。

话虽如此,我认为这是Blaze-Persistence Entity Views的一个完美用例。

我创建了这个库,以便实现JPA模型与自定义接口或抽象类定义的模型之间的轻松映射,有点类似于功能强大的Spring Data Projections。这个想法是,你可以根据自己的喜好定义目标结构(领域模型),并通过JPQL表达式将属性(getter)映射到实体模型。

对于你的用例,使用Blaze-Persistence Entity Views的DTO模型可能如下所示:

@EntityView(Facility.class)
public interface FacilityProjection {
    @IdMapping
    Long getId();
    String getName();
    @Mapping("SIZE(users)")
    Long getUsercount();
}

查询就是将实体视图应用于查询的问题,最简单的方法只是根据ID进行查询。

FacilityProjection a = entityViewManager.find(entityManager, FacilityProjection.class, id);

Spring Data集成允许你几乎像使用Spring Data Projections一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features,因此你可以将其视为支持更多用例的Spring Data Projections的替代品!

英文:

As far as I know, this is not possible.

Having said that, I think this is a perfect use case for Blaze-Persistence Entity Views.

I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.

A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:

@EntityView(Facility.class)
public interface FacilityProjection {
    @IdMapping
    Long getId();
    String getName();
    @Mapping(&quot;SIZE(users)&quot;)
    Long getUsercount();
}

Querying is a matter of applying the entity view to a query, the simplest being just a query by id.

FacilityProjection a = entityViewManager.find(entityManager, FacilityProjection.class, id);

The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features so you can see this as a replacement for Spring Data Projections that supports more use cases!

huangapple
  • 本文由 发表于 2020年9月17日 15:46:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/63933474.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定