使用 Java 8 谓词的 JPA 存储库过滤器 [英] JPA Repository filter using Java 8 Predicates

查看:29
本文介绍了使用 Java 8 谓词的 JPA 存储库过滤器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用 Spring Boot 的一次面试测试中有一个要求,我必须创建一个端点,该端点接受一堆可选的请求参数,然后根据这些参数(如汽车型号、车牌、引擎)返回汽车列表类型、制造商、司机、租赁公司等.而汽车、司机和制造商都是独立的实体.

I had a requirement in one of my interview tests using Spring Boot where I had to create an endpoint that accepts a bunch of optional request params and then returns a list of cars based on these parameters like car model, license plate, engine type, manufacturer, driver, the company it was rent to etc etc. And car, driver and manufacturer are all separate entities.

我在 JPARepository 中使用单个 JPQL 查询实现了此功能,该查询实现了 LEFT JOINS 并在 where 子句中过滤,如 licensePlate = licensePlateParameter OR licensePlatParameter is null 等.

I implement this functionality in JPARepository with a single JPQL query implementing LEFT JOINS and filter in where clause like licensePlate = licensePlateParameter OR licensePlatParameter is null etc.

该解决方案有效,但面试官表示该解决方案具有可扩展性和可维护性.我应该使用谓词来实现它.有人可以向我展示一个示例,我如何使用更易于维护的谓词来实现此类功能?一些带有代码的示例将不胜感激.

The solution was working however the interviewer said the solution was scalable and maintainable. I should have implemented it using predicates. Can someone show me an example how could I implement such functionality using predicates that is easier to maintain? Some examples with code would be greatly appreciated.

我认为我很聪明,通过检查参数是否为空来处理可选参数和在单个调用中找到的记录.我想到的另一个与此相关的问题是,从 DB 获取所有记录然后使用谓词对其进行过滤真的是一个好习惯吗?还有当我们涉及多个对象/实体时如何过滤,可以为单个类型创建谓词.

I thought I was smart by catering both the optional parameters and found records with in a single call by checking if the parameter is null or not. Another question related to that I have in mind is it really a good practice to get all the records from DB and then filter it using predicates? Also how to we filter when we have multiple objects/entities involved, predicates can be created for a single type.

@Query("SELECT d FROM Driver d LEFT JOIN d.car c WHERE (d.name = :name OR :name is null) "
            + "and (c.licensePlate = :licensePlate OR :licensePlate is null) "
            + "and (c.rating = :rating OR :rating is null) " and so on

    List<Driver> findByAttributes(@Param("name") String name, 
            @Param("licensePlate") String licensePlate,
            @Param("rating") Integer rating,
            and so on);

推荐答案

Spring 对 JPA 标准 API(使用谓词)有一个包装器,称为规范 API.

Spring has a wrapper around the JPA criteria API (that uses predicates) and is called the specification API.

在编写规范时可以做的事情如下,为每个标准写一个规范:

What you can do when writing specifications is the following, write a specification for each criteria:

public static Specification<Car> withLicensePlate(String licensePlate) {
    return (root, query, cb) -> licensePlate == null ? null : cb.equal(root.get("licensePlate"), licensePlate);
}

public static Specification<Car> withRating(String rating) {
    return (root, query, cb) -> rating == null ? null : cb.equal(root.get("rating"), rating);
}

public static Specification<Car> withName(String name) {
    return (root, query, cb) -> name == null ? null : cb.equal(root.get("name"), name);
}

它还允许您编写连接操作:

it also allows you to write a join operation as well:

public static Specification<Car> withSeatType(String type) {
    return (root, query, cb) -> {
        return type == null ? null : cb.equal(root.join("interior", JoinType.LEFT).get("type"), type);
    };
}

您可以在条件内返回 null,这允许您将这些规范设为可选".之后,您可以使用 Specifications.where() 组合这些条件:

You can return null within a criteria, which allows you to make these specifications "optional". After that, you can use Specifications.where() to combine these criteria:

 Specification<Car> spec = Specifications
      .where(withLicensePlate(licensePlate))
      .and(withRating(rating))
      .and(withName(name))
      .and(withSeatType(seatType));

如果你像我在这个例子中所做的那样编写单独的规范,你可以在必要时重新使用它们.否则,您将不得不编写特定于操作的规范,而面试官可能也不会发现它具有可扩展性.

If you write separate specifications like I did in this example, you can re-use them where necessary. Otherwise, you'll have to write operation-specific specifications, and the interviewer might not find that scalable either.

编写规范后,您必须从 JpaSpecificationExecutor 接口扩展您的存储库并使用 findAll(Specification) 方法.

After writing the specifications, you have to extend your repository from the JpaSpecificationExecutor interface and use the findAll(Specification) method.

这篇关于使用 Java 8 谓词的 JPA 存储库过滤器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆