2014-12-23 9 views
19

Mit Spring Data JPA kann ich eine query by example tun, wo eine bestimmte Entity-Instanz als Suchkriterium verwendet wird?Federdaten JPA: Abfrage mit Beispiel?

Zum Beispiel (kein Wortspiel beabsichtigt), wenn ich eine Person Einheit, die wie folgt aussieht: ich alle Beschäftigten mit einem Nachnamen Smith

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

am 1. Januar 1977 mit einem Beispiel geboren finden konnte, :

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

Ihre Frage ist nicht klar. was genau suchst du? –

+2

Nein, Sie können nicht, wie dies auf den Winterschlaf beschränkt ist, ist Spring Data für JPA ausgelegt. Sie können immer eine "Spezifikation" erstellen und das ausführen, was Sie dann verwenden könnten, um etwas Ähnliches zu tun. –

Antwort

7

Frühling Daten beruhen auf der JPA und EntityManager, Hibernate und Session nicht, und als solche haben Sie nicht findByExample aus dem Kasten heraus. Sie können die Federdaten automatische Erstellung der Abfrage verwenden und ein Verfahren in Ihrem Repository mit der folgenden Signatur schreiben:

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

JPA! = Ruhezustand. Macht Sinn. Ich denke, dass wir die "Specification" -Route, wie von @M erwähnt, gehen. Deinum ist der Weg dorthin, um mehr Ad-hoc-Abfragen durchführen zu können. –

+1

Sie können sich die Beispiele hier anschauen http://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/. Es kann Ihre Bedürfnisse erfüllen –

+0

Ich öffnete [DATAJPA-844] (https://jira.spring.io/browse/DATAJPA-844), um diese Funktion in Spring Data JPA anzufordern. Es scheint, als wäre es auf ihrer Roadmap! –

19

Frühling Daten Mit Specification Schnittstelle konnte ich die Verwendung von Query By Example anzunähern. Hier ist eine PersonSpec Klasse, die Specification implementiert und erfordert ein "Beispiel" Person, um die Einrichtung des Predicate zurück durch die 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])); 
    } 
} 

Das Repository ist einfach:

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

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

Anwendungsbeispiel:

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

Gut, aber ich muss noch eine Implementierungsklasse für jede Abfrage erstellen, die ich schreiben möchte. –

+1

Woher kommt Person_? –

+0

Person_ ist eine statische Metamodell-Klasse – fyrite

36

Dies ist jetzt mit Spring Data möglich. Check out 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); 

Beachten Sie, dass diese jüngsten Versionen 2016 erfordert

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

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

+0

wow, das ist heiß! Antwort bekam 5 Stimmen an einem Tag –

+0

Was ist mit einer komplexeren Domain? Ich meine, wenn wir Assoziationen haben, wie kann ich das Beispiel verwenden? Irgendeine Idee ? –

+1

Für eine komplexere Domäne verwendete ich am Ende QueryDSL mit Spring Data JPA. Nahm mich ein bisschen, um zu lernen und wickelte meinen Kopf herum, aber wir am Ende tatsächlich unsere Code-Basis Refactoring und Beseitigung der Beispiel Verwendung vollständig. –

Verwandte Themen