查询方法中的Spring Data可选参数

时间:2015-09-22 23:47:10

标签: spring hibernate spring-data spring-data-jpa jpql

我想在存储库层中编写一些查询方法。此方法必须忽略null参数。例如:

List<Foo> findByBarAndGoo(Bar barParam, @optional Goo gooParam);

此方法必须通过以下条件返回Foo:

bar == barParam && goo == gooParam;

如果gooParam不为空。如果gooParam为null,则条件更改为:

bar == barParam;

有什么解决方案吗?有人能帮助我吗?

5 个答案:

答案 0 :(得分:19)

我不相信您能够使用方法名称方法来查询定义。从文档(reference):

  

虽然获取从方法名称派生的查询是相当的   方便,一个人可能面临其中任何一种方法的情况   name parser不支持想要使用的关键字或方法   名字会变得不必要的丑陋。所以你可以使用JPA命名   通过命名约定查询(请参阅使用JPA NamedQueries)   更多信息)或者更确切地说使用@Query

注释您的查询方法

我认为你有这种情况,所以下面的答案使用@Query注释方法,这几乎和方法名称方法(reference)一样方便。

    @Query("select foo from Foo foo where foo.bar = :bar and "
        + "(:goo is null or foo.goo = :goo)")
    public List<Foo> findByBarAndOptionalGoo(
        @Param("bar") Bar bar, 
        @Param("goo") Goo goo);

答案 1 :(得分:8)

补充@chaserb的答案,我个人会将参数添加为Java8 Optional类型,以使其在方法的签名中显式为可选过滤器的语义。

@Query("select foo from Foo foo where foo.bar = :bar and "
   + "(:goo is null or foo.goo = :goo)")
public List<Foo> findByBarAndOptionalGoo(
     @Param("bar") Bar bar, 
     @Param("goo") Optional<Goo> goo);

答案 2 :(得分:6)

回答太迟了。不确定 Bar Goo 之间的关系。检查示例是否可以帮助您。

它对我有用。我有类似的情况,实体用户有一组属性,并且有 findAll 方法,它根据属性(可选)搜索用户。

实施例,

  Class User{
    String firstName;
    String lastName;
    String id;
  }

  Class UserService{
     // All are optional
     List<User> findBy(String firstName, String lastName, String id){
        User u = new User();
        u.setFirstName(firstName);
        u.setLastName(lastName);
        u.setId(id);

        userRepository.findAll(Example.of(user));
        // userRepository is a JpaRepository class
     }
  }

答案 3 :(得分:4)

您可以使用 JpaSpecificationExecutor //import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

第 1 步:在您的 JPA 存储库中实现 JpaSpecificationExecutor

例如:

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

第 2 步现在要根据可选参数获取票证,您可以使用 CriteriaBuilder 构建规范查询

例如:

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]));
    };
}

第 3 步:将 Specification 实例传递给 jpaRepo.findAll(specification),它将返回您的实体对象列表(运行示例中的票证)

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

答案 4 :(得分:0)

你可以自己编写几行代码:

List<Foo> findByBarAndOptionalGoo(Bar bar, Goo goo) {
   return (goo == null) ? this.findByBar(bar) : this.findByBarAndGoo(bar, goo);
}

否则,我不知道Spring-Data是否支持开箱即用。