简体   繁体   English

带有可选@Param 的 Spring 数据查询方法

[英]Spring Data Query Method with Optional @Param

Is it possible to allow query method @Params to be optional, specifically in the case of Spring Data REST?是否可以允许查询方法 @Params 是可选的,特别是在 Spring Data REST 的情况下?

For example, I'd like to bind a very similar search to the same resource path.例如,我想将一个非常相似的搜索绑定到相同的资源路径。 To do this now, I would need something like the following:现在要做到这一点,我需要如下内容:

@RestResource(path = "driver", rel = "byDriver")
List<Bar> findByDriverId(@Param("id") String id, Pageable pageable);

@RestResource(path = "driverAndSpan", rel = "byDriverAndSpan")
List<Bar> findByDriverIdAndStartTimeGreaterThanEqualAndEndTimeLessThanEqual(@Param("id") String id, @Param("start") Date start,
        @Param("end") Date end, Pageable pageable);

Which gives me:这给了我:

byDriver: {
  href: "http://localhost:8080/foo/search/driver{?id,page,size,sort}",
},
byDriverAndSpan: {
  href: "http://localhost:8080/foo/search/driverAndSpan{?id,start,end,page,size,sort}",
}

What I want is to be able to see something like the following path, where start and end are optional parameters, rather than defining multiple methods in my Repository.想要的是能够看到类似于以下路径的内容,其中startend是可选参数,而不是在我的 Repository 中定义多个方法。

byDriverAndSpan: {
  href: "http://localhost:8080/foo/search/driverAndSpan{?id,*start,*end,page,size,sort}",
}

Which could potentially look like:这可能看起来像:

@RestResource(path = "driverAndSpan", rel = "byDriverAndSpan")
List<Bar> findByDriverIdAndStartTimeGreaterThanEqualAndEndTimeLessThanEqual(@Param("id") String id, @Param(value = "start", optional = true) Date start,
        @Param(value = "end", optional = true) Date end, Pageable pageable);

Maybe you can define a 'main' function as default which will delegate to the other functions.也许您可以将“main”函数定义为default ,该函数将委托给其他函数。 Something like this像这样的东西

@RestResource(path = "driverAndSpan", rel = "byDriverAndSpan")
default List<Bar> findByDriverIdAndOptionalStartTimeGreaterThanEqualAndOptionalEndTimeLessThanEqual(@Param("id") String id, @Param(value = "start", optional = true) Date start,
        @Param(value = "end", optional = true) Date end, Pageable pageable) {
   if(start != null && end != null) {
      return findByDriverIdAndStartTimeGreaterThanEqualAndEndTimeLessThanEqual(id, start, end, pageable);
   }
   return findByDriverId(id, pageable);
}

I think you can even use Optional as a parameter type, then you can use function overloading我觉得你甚至可以使用Optional作为参数类型,然后你可以使用函数重载

@RestResource(path = "driverAndSpan", rel = "byDriverAndSpan")
default List<Bar> findByDriverIdAndStartTimeGreaterThanEqualAndEndTimeLessThanEqual(
@Param("id") String id, @Param(value = "start") Optional<Date> start,
        @Param(value = "end") Optional<Date> end, Pageable pageable) {
   if (!start.isEmpty() && !end.isEmpty()) {
      return findByDriverIdAndStartTimeGreaterThanEqualAndEndTimeLessThanEqual(id, start.get(), end.get(), pageable);
   }
   return findByDriverId(id, pageable);
}

List<Bar> findByDriverIdAndStartTimeGreaterThanEqualAndEndTimeLessThanEqual(String id, Date start, Date end, Pageable pageable);

Notice that in this case, you shouldn't expose the other endpoints, and only expose this default method.请注意,在这种情况下,您不应公开其他端点,而应仅公开此默认方法。

No, this is currently not supported.不,目前不支持此功能。 If it was there would be the risk of ambiguity.如果是这样,就会有歧义的风险。 There could be the scenario where the incoming url could match more than 1 @RestResource .可能存在传入 url 匹配超过 1 个@RestResource

To explain from a Java point of view lets say we could define two methods:为了从 Java 的角度进行解释,假设我们可以定义两种方法:

getPerson(String firstName, int age);

getPerson(String firstName, {Optional} int age, int phoneNumber);

There would be issues when someone is aiming to invoke the second method, not supplying age but being mapped to the first method with the phoneNumber being read as an age.当有人打算调用第二种方法时会出现问题,而不是提供年龄,而是映射到第一种方法,并将 phoneNumber 作为年龄读取。

As UserF40 said, this isn't supported.正如 UserF40 所说,这不受支持。 We faced a similar issue and solved it by dynamically building queries depending on which Optional parameters were supplied.我们遇到了类似的问题,并通过根据提供的 Optional 参数动态构建查询来解决它。

You can use the Criteria API to achieve this, or by dynamically building the SQL in another service class by checking which parameters are present.您可以使用 Criteria API 来实现这一点,或者通过检查存在哪些参数在另一个服务类中动态构建 SQL。

Use org.springframework.data.jpa.repository.JpaSpecificationExecutor;`使用 org.springframework.data.jpa.repository.JpaSpecificationExecutor;`

Step 1 : Implement JpaSpecificationExecutor in your JPA Repository第 1 步:在您的 JPA 存储库中实现JpaSpecificationExecutor

Ex:前任:

public interface TicketRepo extends JpaRepository<Ticket, Long>, JpaSpecificationExecutor<Ticket> {

Step 2 Now to fetch tickets based on optional parameters you can build Specification query using CriteriaBuilder第 2 步现在根据可选参数获取票证,您可以使用 CriteriaBuilder 构建规范查询

Ex:前任:

public Specification<Ticket> getTicketQuery(Integer domainId, Calendar startDate, Calendar endDate, Integer gameId, Integer drawId) {
    return (root, query, criteriaBuilder) -> {
        List<Predicate> predicates = new ArrayList<>();

        predicates.add(criteriaBuilder.equal(root.get("domainId"), domainId));
        predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createdAt"), startDate));
        predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("createdAt"), endDate));

        if (gameId != null) {
            predicates.add(criteriaBuilder.equal(root.get("gameId"), gameId));
        }

        return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
    };
}

Step 3: Pass the Specification instance to jpaRepo.findAll(specification), it will return you the list of your entity object (Tickets here in the running example)第 3 步:将 Specification 实例传递给 jpaRepo.findAll(specification),它将返回您的实体对象列表(运行示例中的票证)

ticketRepo.findAll(specification); // Pass output of function in step 2 to findAll

There is a " required " parameter option in @Param that you can use. @Param 中有一个“ required ”参数选项可供您使用。

@RestResource(path = "driverAndSpan", rel = "byDriverAndSpan") @RestResource(path = "driverAndSpan", rel = "byDriverAndSpan")

List findByDriverIdAndStartTimeGreaterThanEqualAndEndTimeLessThanEqual(@Param("id") String id, @Param(value = "start", required = false) Date start, @Param(value = "end", required = false) Date end, Pageable pageable);列出 findByDriverIdAndStartTimeGreaterThanEqualAndEndTimeLessThanEqual(@Param("id") String id, @Param(value = "start", required = false) 日期开始,@Param(value = "end", required = false) 日期结束,Pageable pageable);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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