简体   繁体   中英

AND operation between all the JPA Specifications Query

I am receiving a queryParam from a controller which is a map, to query the data based on the provided map. I want to use specifications but I am not sure how can I do AND operation between all of them. I would appreciate any suggestion.

Here is my criteria class:

 public class DriverSpecs {

    private final static String CAR_FIELD = "carDO";

    public Specification<DriverDO> getDriversBySpecification(Map<String, String> queryParams) {

        queryParams.keySet().forEach(k -> {
            if (k.toLowerCase().contains("username")){
                getDriversByUsername(queryParams.get(k));
            } else if (k.toLowerCase().contains("rating")){
                getDriversByCarRating(queryParams.get(k));
            }
            // ...
        });


        // do AND operation for all the specifications and return it
        return null;
    }

    public static Specification<DriverDO> getDriversByUsername(String username) {
        return ((root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(root.get("username"), username));
    }

    public static Specification<DriverDO> getDriversByOnlineStatus(String onlineStatus) {
        return ((root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(root.get("onlineStatus"), onlineStatus));
    }

    public static Specification<DriverDO> getDriverByCarSeat(short seatCount) {
        return specificationWithCarJoin("seatCount", seatCount);
    }

    public static Specification<DriverDO> getDriversByCarConvertableType(boolean convertible) {
        return specificationWithCarJoin("convertible", convertible);
    }

    public static Specification<DriverDO> getDriversByCarRating(String rating) {
        return specificationWithCarJoin("rating", rating.toUpperCase());
    }

    private static Specification<DriverDO> specificationWithCarJoin(String getField, Object field) {
        return (root, criteriaQuery, criteriaBuilder) -> {
            Join<DriverDO, CarDO> carJoin = root.join(CAR_FIELD);
            return criteriaBuilder.equal(carJoin.get(getField), field);
        };
    }
}

Use Stream API for this. Map all the parameters into a specification and then reduce it to a single specification. Like this

Optional<Specification<DriverDO>> reduce = queryParams.keySet().stream().map(k -> {
        if (k.toLowerCase().contains("username")){
            return getDriversByUsername(queryParams.get(k));
        } else if (k.toLowerCase().contains("rating")){
            return  getDriversByCarRating(queryParams.get(k));
        }
        // ...
    }).reduce((a, b) -> a.and(b));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM