如何使用 fetch 或 fetchResults 正确获取 Page 作为 Querydsl 查询的结果?
How to get Page as result in Querydsl query with fetch or fetchResults properly?
您好,我想在这里实现的是,我想将可分页数据提交到 QueryDsl 查询中并获得结果作为页面,我该如何正确地做到这一点?这是我到目前为止所做的:
这是我的控制器:
@PostMapping("/view-latest-stock-by-product-codes")
public ResponseEntity<RequestResponseDTO<Page<StockAkhirResponseDto>>> findStockByProductCodes(
@RequestBody StockViewByProductCodesDto request) {
Page<StockAkhirResponseDto> stockAkhir = stockService.findByBulkProduct(request);
return ResponseEntity.ok(new RequestResponseDTO<>(PESAN_TAMPIL_BERHASIL, stockAkhir));
}
在我的控制器中,我提交了如下所示的 StockViewByProductCodesDto:
@Data
public class StockViewByProductCodesDto implements Serializable {
private static final long serialVersionUID = -2530161364843162467L;
@Schema(description = "Kode gudang yang ingin di tampilkan", example = "GBKTJKT1", required = true)
private String warehouseCode;
@Schema(description = "id dari sebuah branch", example = "1", required = true)
private Long branchId;
@Schema(description = "Kode Branch", example = "JKT", required = true)
private String branchCode;
@Schema(description = "Kode Product yang merupakan kode yang di ambil dari master product", example = "[\"MCM-508\",\"TL-101\"]", required = true)
private List<String> productCodes;
@Schema(description = "Size of row per page", example = "15", required = true)
@NotNull
private int size;
@Schema(description = "Page number", example = "1", required = true)
@NotNull
private int page;
@Schema(description = "Sort by", example = "id", required = false)
private String sort;
}
这是我的服务:
public Page<StockAkhirResponseDto> findByBulkProduct(StockViewByProductCodesDto request) {
String warehouseCode = request.getWarehouseCode();
Long branchId = request.getBranchId();
String branchCode = request.getBranchCode();
List<String> productCodes = request.getProductCodes();
Set<String> productCodesSet = new HashSet<String>(productCodes);
Pageable pageable = PageUtils.pageableUtils(request);
Page<StockAkhirResponseDto> stockAkhir = iStockQdslRepository.findBulkStockAkhirPage(warehouseCode, branchId, branchCode, productCodesSet, pageable);
return stockAkhir;
}
如您所见,我使用 PageUtils.pageableUtils(请求)提取可分页信息,这是我的 pageableUtils 函数,如下所示:
public static Pageable pageableUtils(RequestKeyword request) {
int page = 0;
int size = 20;
if (request.getPage() > 0) {
page = request.getPage() - 1;
}
if (request.getSize() > 0) {
size = request.getSize();
}
if (!request.getSort().isEmpty()) {
return PageRequest.of(page, size, Sort.by(request.getSort()).descending());
} else {
return PageRequest.of(page, size);
}
}
获得 Pageable 数据后,我将其提交到我的存储库中,它看起来像这样:
public Page<StockAkhirResponseDto> findBulkStockAkhirPage(String warehouseCode, Long branchId, String branchCode,
Set<String> productCodes, Pageable pageable) {
JPQLQuery<Tuple> query = new JPAQuery<>(em);
long offset = pageable.getOffset();
long limit = pageable.getPageSize();
QStock qStock = QStock.stock;
NumberExpression<Integer> totalQty = qStock.qty.sum().intValue();
query = query.select(qStock.productId, qStock.productCode, totalQty).from(qStock)
.where(qStock.warehouseCode.eq(warehouseCode), qStock.productCode.in(productCodes),
qStock.branchCode.eq(branchCode), qStock.branchId.eq(branchId))
.groupBy(qStock.productId, qStock.productCode);
query.limit(limit);
query.offset(offset);
QueryResults<Tuple> result = query.fetchResults();
long total = result.getTotal();
List<Tuple> rows = result.getResults();
List<StockAkhirResponseDto> stockAkhirDto = rows.stream()
.map(t -> new StockAkhirResponseDto(t.get(0, Long.class), t.get(1, String.class), t.get(2, Integer.class)))
.collect(Collectors.toList());
return new PageImpl<>(stockAkhirDto, pageable, total);
}
查看我的存储库时我的编辑器没有错误,我可以 运行 我的项目,但是当我执行我的存储库功能时,我得到了这个错误:
"org.hibernate.hql.internal.ast.QuerySyntaxException: expecting CLOSE,
found ',' near line 1, column 38 [select count(distinct
stock.productId, stock.productCode, stock.warehouseId,
stock.warehouseCode, stock.branchCode, stock.branchId)\nfrom
com.bit.microservices.b2b.warehouse.entity.Stock stock\nwhere
stock.warehouseCode = ?1 and stock.productCode in ?2 and
stock.branchCode = ?3 and stock.branchId = ?4]; nested exception is
java.lang.IllegalArgumentException:
org.hibernate.hql.internal.ast.QuerySyntaxException: expecting CLOSE,
found ',' near line 1, column 38 [select count(distinct
stock.productId, stock.productCode, stock.warehouseId,
stock.warehouseCode, stock.branchCode, stock.branchId)\nfrom
com.bit.microservices.b2b.warehouse.entity.Stock stock\nwhere
stock.warehouseCode = ?1 and stock.productCode in ?2 and
stock.branchCode = ?3 and stock.branchId = ?4]"
问题出在这里,在这一行:
QueryResults<Tuple> result = query.fetchResults();
当我执行该行时,它给了我那个错误,我尝试获取 fetchResult,因为我想获取总数的 .getTotal()。
但是如果我使用 .fetch() 执行查询,它工作正常,就像这样:
List<StockAkhirResponseDto> stockAkhirDto = query.fetch()
我的 sql 结果正确执行,我错过了什么?如何正确获取页面结果?
您的问题可能与打开的 QueryDSL issue 有关。记录的问题与 fetchCount
的使用有关,但我认为很可能也是您的情况。
考虑上述问题中的以下 comment:
fetchCount()
uses a COUNT
function, which is an aggregate function. Your query already has aggregate functions. You cant aggregate aggregate functions, unless a subquery is used (which is not available in JPA). Therefore this use case cannot be supported.
该issue还提供了temporary solution.
基本上,想法是能够通过在初始 select 上创建语句来执行 COUNT
。据我所知,QueryDsl 是不可能的,这就是为什么在指定的解决方法中他们访问 Hibernate 提供的下划线机制。
也许,您可以尝试避免限制的另一件事是为您的查询创建一个数据库视图,在其上创建相应的 QueryDsl 对象,并使用这些对象执行实际计算。我知道这不是一个理想的解决方案,但它会绕过当前的 QueryDsl 限制。
您好,我想在这里实现的是,我想将可分页数据提交到 QueryDsl 查询中并获得结果作为页面,我该如何正确地做到这一点?这是我到目前为止所做的:
这是我的控制器:
@PostMapping("/view-latest-stock-by-product-codes")
public ResponseEntity<RequestResponseDTO<Page<StockAkhirResponseDto>>> findStockByProductCodes(
@RequestBody StockViewByProductCodesDto request) {
Page<StockAkhirResponseDto> stockAkhir = stockService.findByBulkProduct(request);
return ResponseEntity.ok(new RequestResponseDTO<>(PESAN_TAMPIL_BERHASIL, stockAkhir));
}
在我的控制器中,我提交了如下所示的 StockViewByProductCodesDto:
@Data
public class StockViewByProductCodesDto implements Serializable {
private static final long serialVersionUID = -2530161364843162467L;
@Schema(description = "Kode gudang yang ingin di tampilkan", example = "GBKTJKT1", required = true)
private String warehouseCode;
@Schema(description = "id dari sebuah branch", example = "1", required = true)
private Long branchId;
@Schema(description = "Kode Branch", example = "JKT", required = true)
private String branchCode;
@Schema(description = "Kode Product yang merupakan kode yang di ambil dari master product", example = "[\"MCM-508\",\"TL-101\"]", required = true)
private List<String> productCodes;
@Schema(description = "Size of row per page", example = "15", required = true)
@NotNull
private int size;
@Schema(description = "Page number", example = "1", required = true)
@NotNull
private int page;
@Schema(description = "Sort by", example = "id", required = false)
private String sort;
}
这是我的服务:
public Page<StockAkhirResponseDto> findByBulkProduct(StockViewByProductCodesDto request) {
String warehouseCode = request.getWarehouseCode();
Long branchId = request.getBranchId();
String branchCode = request.getBranchCode();
List<String> productCodes = request.getProductCodes();
Set<String> productCodesSet = new HashSet<String>(productCodes);
Pageable pageable = PageUtils.pageableUtils(request);
Page<StockAkhirResponseDto> stockAkhir = iStockQdslRepository.findBulkStockAkhirPage(warehouseCode, branchId, branchCode, productCodesSet, pageable);
return stockAkhir;
}
如您所见,我使用 PageUtils.pageableUtils(请求)提取可分页信息,这是我的 pageableUtils 函数,如下所示:
public static Pageable pageableUtils(RequestKeyword request) {
int page = 0;
int size = 20;
if (request.getPage() > 0) {
page = request.getPage() - 1;
}
if (request.getSize() > 0) {
size = request.getSize();
}
if (!request.getSort().isEmpty()) {
return PageRequest.of(page, size, Sort.by(request.getSort()).descending());
} else {
return PageRequest.of(page, size);
}
}
获得 Pageable 数据后,我将其提交到我的存储库中,它看起来像这样:
public Page<StockAkhirResponseDto> findBulkStockAkhirPage(String warehouseCode, Long branchId, String branchCode,
Set<String> productCodes, Pageable pageable) {
JPQLQuery<Tuple> query = new JPAQuery<>(em);
long offset = pageable.getOffset();
long limit = pageable.getPageSize();
QStock qStock = QStock.stock;
NumberExpression<Integer> totalQty = qStock.qty.sum().intValue();
query = query.select(qStock.productId, qStock.productCode, totalQty).from(qStock)
.where(qStock.warehouseCode.eq(warehouseCode), qStock.productCode.in(productCodes),
qStock.branchCode.eq(branchCode), qStock.branchId.eq(branchId))
.groupBy(qStock.productId, qStock.productCode);
query.limit(limit);
query.offset(offset);
QueryResults<Tuple> result = query.fetchResults();
long total = result.getTotal();
List<Tuple> rows = result.getResults();
List<StockAkhirResponseDto> stockAkhirDto = rows.stream()
.map(t -> new StockAkhirResponseDto(t.get(0, Long.class), t.get(1, String.class), t.get(2, Integer.class)))
.collect(Collectors.toList());
return new PageImpl<>(stockAkhirDto, pageable, total);
}
查看我的存储库时我的编辑器没有错误,我可以 运行 我的项目,但是当我执行我的存储库功能时,我得到了这个错误:
"org.hibernate.hql.internal.ast.QuerySyntaxException: expecting CLOSE, found ',' near line 1, column 38 [select count(distinct stock.productId, stock.productCode, stock.warehouseId, stock.warehouseCode, stock.branchCode, stock.branchId)\nfrom com.bit.microservices.b2b.warehouse.entity.Stock stock\nwhere stock.warehouseCode = ?1 and stock.productCode in ?2 and stock.branchCode = ?3 and stock.branchId = ?4]; nested exception is java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: expecting CLOSE, found ',' near line 1, column 38 [select count(distinct stock.productId, stock.productCode, stock.warehouseId, stock.warehouseCode, stock.branchCode, stock.branchId)\nfrom com.bit.microservices.b2b.warehouse.entity.Stock stock\nwhere stock.warehouseCode = ?1 and stock.productCode in ?2 and stock.branchCode = ?3 and stock.branchId = ?4]"
问题出在这里,在这一行:
QueryResults<Tuple> result = query.fetchResults();
当我执行该行时,它给了我那个错误,我尝试获取 fetchResult,因为我想获取总数的 .getTotal()。
但是如果我使用 .fetch() 执行查询,它工作正常,就像这样:
List<StockAkhirResponseDto> stockAkhirDto = query.fetch()
我的 sql 结果正确执行,我错过了什么?如何正确获取页面结果?
您的问题可能与打开的 QueryDSL issue 有关。记录的问题与 fetchCount
的使用有关,但我认为很可能也是您的情况。
考虑上述问题中的以下 comment:
fetchCount()
uses aCOUNT
function, which is an aggregate function. Your query already has aggregate functions. You cant aggregate aggregate functions, unless a subquery is used (which is not available in JPA). Therefore this use case cannot be supported.
该issue还提供了temporary solution.
基本上,想法是能够通过在初始 select 上创建语句来执行 COUNT
。据我所知,QueryDsl 是不可能的,这就是为什么在指定的解决方法中他们访问 Hibernate 提供的下划线机制。
也许,您可以尝试避免限制的另一件事是为您的查询创建一个数据库视图,在其上创建相应的 QueryDsl 对象,并使用这些对象执行实际计算。我知道这不是一个理想的解决方案,但它会绕过当前的 QueryDsl 限制。