Spring Data JPA:通过示例查询?

Posted

技术标签:

【中文标题】Spring Data JPA:通过示例查询?【英文标题】:Spring Data JPA: Query by Example? 【发布时间】:2015-02-21 23:26:55 【问题描述】:

使用 Spring Data JPA,我可以在 query by example 中使用特定实体实例作为搜索条件吗?

例如(没有双关语),如果我有一个 Person 实体,看起来像:

@Entity
public class Person 
  private String firstName;
  private String lastName;
  private boolean employed;
  private LocalDate dob;
  ...

我可以找到所有姓氏为 Smith 出生于 1977 年 1 月 1 日的雇员,例如:

Person example = new Person();
example.setEmployed(true);
example.setLastName("Smith");
example.setDob(LocalDate.of(1977, Month.JANUARY, 1));
List<Person> foundPersons = personRepository.findByExample(example);

【问题讨论】:

您的问题不清楚。您到底在寻找什么? 不,你不能,因为它仅限于休眠,Spring Data 是为 JPA 设计的。你总是可以创建一个Specification 并执行你可以用来做类似事情的那个。 【参考方案1】:

现在可以使用 Spring Data。查看http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#query-by-example

Person person = new Person();                         
person.setLastname("Smith");                          
Example<Person> example = Example.of(person);
List<Person> results = personRepository.findAll(example);

请注意,这需要最新的 2016 版本

    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>1.10.1.RELEASE</version>       
    </dependency>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-commons</artifactId>
        <version>1.12.1.RELEASE</version>
    </dependency>

见https://github.com/paulvi/com.example.spring.findbyexample

【讨论】:

更复杂的域怎么样。我的意思是当我们有关联时,我该如何使用示例?有什么想法吗? 对于更复杂的域,我最终将 QueryDSL 与 Spring Data JPA 结合使用。我花了一些时间来学习和思考,但我们最终实际上重构了我们的代码库并完全消除了示例的使用。 复杂的嵌套域没有问题。使用您需要的所有关联创建一个域对象,Example.of(x) 将完成这项工作。可悲的是,我在日期对象上遇到了“介于”的问题。 can't do between, lessThan greaterThan.... spring teamp 没有兴趣添加此功能...或接受 pull request...【参考方案2】:

Spring 数据依赖于 JPA 和 EntityManager,而不是 Hibernate 和 Session,因此您没有开箱即用的 findByExample。您可以使用spring数据自动查询创建并在您的存储库中编写一个具有以下签名的方法:

List<Person> findByEmployedAndLastNameAndDob(boolean employed, String lastName, LocalDate dob);

【讨论】:

JPA != 休眠。说得通。我想走@M 提到的Specification 路线。 Deinum 是去这里的方式,因为我希望能够执行更多的临时查询。 您可以在这里查看示例spring.io/blog/2011/04/26/…。它可以满足您的需求 我在 Spring Data JPA 中打开了DATAJPA-844 以请求此功能。这似乎在他们的路线图上! 这个答案现在已经过时了【参考方案3】:

使用 Spring 数据的 Specification 接口,我能够通过示例来近似查询的使用。这是一个PersonSpec 类,它实现了Specification,并且需要一个“示例”人员来设置Specification 返回的Predicate

public class PersonSpec implements Specification<Person> 

  private final Person example;

  public PersonSpec(Person example) 
    this.example = example;
  

  @Override
  public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> cq, CriteriaBuilder cb) 
    List<Predicate> predicates = new ArrayList<>();

    if (StringUtils.isNotBlank(example.getLastName())) 
      predicates.add(cb.like(cb.lower(root.get(Person_.lastName)), example.getLastName().toLowerCase() + "%"));
    

    if (StringUtils.isNotBlank(example.getFirstName())) 
      predicates.add(cb.like(cb.lower(root.get(Person_.firstName)), example.getFirstName().toLowerCase() + "%"));
    

    if (example.getEmployed() != null) 
      predicates.add(cb.equal(root.get(Person_.employed), example.getEmployed()));
    

    if (example.getDob() != null) 
      predicates.add(cb.equal(root.get(Person_.dob), example.getDob()));
    

    return andTogether(predicates, cb);
  

  private Predicate andTogether(List<Predicate> predicates, CriteriaBuilder cb) 
    return cb.and(predicates.toArray(new Predicate[0]));
  

存储库很简单:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

public interface PersonRepository extends JpaRepository<Person, Long>, JpaSpecificationExecutor 

使用示例:

Person example = new Person();
example.setLastName("James");
example.setEmployed(true);
PersonSpec personSpec = new PersonSpec(example);
List<Person> persons = personRepository.findAll(personSpec);

【讨论】:

很好,但我仍然需要为每个要编写的查询创建一个实现类。 Person_ 来自哪里? 规范写起来有点长...如果能够在不编写所有这些代码的情况下通过反射搜索所有字段可能会更有趣... @PaulVerest Person_ 可以使用类似的库生成,例如hibernate-jpamodelgen。尽管如此,我还是使用了 Lombok 注释 FieldNameConstants

以上是关于Spring Data JPA:通过示例查询?的主要内容,如果未能解决你的问题,请参考以下文章

Spring-Data-JPA 中的查询如何动态组装条件?

如何在 Spring Data (JPA) 派生查询中按多个属性排序?

spring-data-jpa 存储库模式与 Querydsl 查询模式有啥区别?

Spring Data JPA 通过查询从实体获取投影

是否有适用于 JPA、spring-data、spring-data-rest 的通用 REST 查询语言

Spring Data 系列学习Spring Data JPA 基础查询