web-dev-qa-db-fra.com

Spring Data JPA: interroger par exemple?

À l'aide de Spring Data JPA, puis-je effectuer un requête par exemple où une instance d'entité particulière est utilisée comme critère de recherche?

Par exemple (sans jeu de mots), si j’ai une entité Person qui ressemble à ceci:

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

Je pourrais trouver toutes les personnes employées portant le nom de famille Smith nées le 1 er janvier 1977 avec un exemple:

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

Les données de printemps reposent sur JPA et EntityManager, et non sur Hibernate et Session. Par conséquent, findByExample n'est pas prêt à l'emploi. Vous pouvez utiliser la création automatique de requête de données de printemps et écrire une méthode dans votre référentiel avec la signature suivante:

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

C'est maintenant possible avec Spring Data. Départ 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);

Notez que cela nécessite des versions 2016 très récentes

    <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>

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

63
Adam Erstelle

En utilisant l'interface Specification de Spring data, j'ai pu approximer l'utilisation de requête par exemple. Voici une classe PersonSpec qui implémente Specification et nécessite un "exemple" pour pouvoir configurer le Predicate renvoyé par le Specification:

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

Le référentiel est simplement:

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

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

Exemple d'utilisation:

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