【问题标题】:Java how to transform List<Object> to Page from JPA paginationJava如何将List<Object>从JPA分页转换为Page
【发布时间】:2022-01-05 21:43:39
【问题描述】:

我的 Jpa 存储库中的自定义搜索方法有问题。我将此方法实现为自定义 serach,在此方法中,我的 SQL 库中有 List,我尝试将其转换为 JPA 分页和排序中的 Page 对象,但是方式我试图这样做是行不通的。这只是分页的错觉,因为在邮递员/互联网浏览器中,我看到列表中的所有元素,当我更改端点中的页面和大小值时,什么都没有改变。 有人知道怎么帮忙吗?

GitHub 项目:https://github.com/s0bieskii/DemoCarRental

我来自 Controller 的端点:

@GetMapping("/find")
ResponseEntity<Page<CarDTO>> readAllCarsFiltered(@RequestParam(defaultValue = "0") int page,
                                                 @RequestParam(defaultValue = "5") int size,
                                                 Pageable pageable,
                                                 @RequestParam(required = false) String brand,
                                                 @RequestParam(required = false) String model,
                                                 @RequestParam(required = false) String type,
                                                 @RequestParam(required = false) Integer registrationYear,
                                                 @RequestParam(required = false) String color,
                                                 @RequestParam(required = false) String fuel,
                                                 @RequestParam(required = false) String transmission,
                                                 @RequestParam(required = false) String doors,
                                                 @RequestParam(required = false, defaultValue = "9999999999") double price) {
    return ResponseEntity.ok(carService.customerSearch(pageable,
            brand, model, type, registrationYear, color, fuel, transmission, doors, price));
}

我的服务

public Page<CarDTO> customerSearch(Pageable pageable, String brand, String model, String type, Integer registrationNumber, String color,
                                   String fuel, String transmission, String doors, double price){

    return carRepository.search(pageable, brand, model, type, registrationNumber, color, fuel, transmission, doors, price)
            .map(car -> carMapper.carToDto(car));
}

我在 RepositoryImplementation 中的自定义搜索方法

 @Override
    public Page<Car> search(Pageable pageable, String brand, String model, String type, Integer registrationYear, String color,
                            String fuel, String transmission, String doors, double price) {
        int var = 0;
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<Car> query = cb.createQuery(Car.class);
        Root<Car> car = query.from(Car.class);
        query.select(car);
        Predicate predicate = cb.greaterThan(car.get("id"), var);

        if (brand != null) predicate = cb.and(predicate, cb.equal(car.get("brand"), brand));
        if (model != null) predicate = cb.and(predicate, cb.equal(car.get("model"), model));
        if (type != null) predicate = cb.and(predicate, cb.equal(car.get("type"), type));
        if (registrationYear != null)
            predicate = cb.and(predicate, cb.equal(car.get("registrationNumber"), registrationYear));
        if (color != null) predicate = cb.and(predicate, cb.equal(car.get("color"), color));
        if (fuel != null) predicate = cb.and(predicate, cb.equal(car.get("fuel"), Fuel.stringToFuelEnum(fuel)));
        if (transmission != null)
            predicate = cb.and(predicate, cb.equal(car.get("transmission"), Transmission.stringToTransmissionEnum(transmission)));
        if (doors != null) predicate = cb.and(predicate, cb.equal(car.get("doors"), doors));
        if (price != 0) predicate = cb.and(predicate, cb.lessThan(car.get("price"), price));
        //predicate = cb.and(predicate, cb.equal(car.get("available"), available));
        List<Car> carList=entityManager.createQuery(query.where(predicate)).getResultList();

        return new PageImpl<Car>(carList, pageable,carList.size());
    }
}

【问题讨论】:

  • 您是否考虑过使用 Querydsl 而不是自己编写所有这些?

标签: java spring arraylist spring-data-jpa pagination


【解决方案1】:

当您执行自定义查询并希望使用 Pageable 时,您需要实现一个逻辑来为您的结果列表创建分页。在你的情况下你没有这样做,所以它可能(你说它不起作用,但没有说什么不起作用,所以我只能猜测)只是返回整个结果列表而不应用分页。

一个简单的解决方案是使用sublist 并将该操作的结果用作PageImpl 的参数。最大的问题是您仍然在后台从数据库中获取整个结果列表,这会产生不必要的开销。

您也可以使用

调整您的查询
em.createQuery(query.where(predicate))
      .setFirstResult(offset)
     .setMaxResults(limit)
     .getResultList()

现在分页是在数据库中完成的,这好多了。

或者您可以省去一些麻烦并使用 Springs Specification 接口而不是创建自己的搜索方法。

首先您的CarRepository 需要扩展JpaSpecificationExecutor。现在 spring 将为您的存储库生成一个findAll(Specification, Pageable) 方法。

第二步是创建搜索规范:

public class SearchSpecification implements Specification<Car> {
    private final String brand;
    private final String model
    private final String type
    private final Integer registrationYear
    private final String color
    private final String fuel
    private final String transmission
    private final String doors
    private final double price

    // constructor & maybe getter
    public Predicate toPredicate(Root<Car> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
        // Create your search predicate
    }
}

现在您只需调用carRepository.findAll(new SearchSpecification (/* parameters */), pageable);,spring 就会为您进行分页。

【讨论】:

  • 非常感谢对我有用 :)
猜你喜欢
  • 1970-01-01
  • 2021-08-08
  • 2019-11-12
  • 1970-01-01
  • 2013-04-01
  • 1970-01-01
  • 2019-12-06
  • 2023-03-08
  • 2017-04-07
相关资源
最近更新 更多