1. Introduzione
In questo tutorial, impareremo come eseguire query sui dati con l'API Spring Data Query by Example .
Per prima cosa, definiremo lo schema dei dati che vogliamo interrogare. Successivamente, esamineremo alcune delle classi rilevanti di Spring Data. Quindi, esamineremo alcuni esempi.
Iniziamo!
2. I dati del test
I nostri dati di prova sono un elenco dei nomi dei passeggeri e del posto che occupavano.
Nome di battesimo | Cognome | Numero del posto |
---|---|---|
Jill | fabbro | 50 |
vigilia | Jackson | 94 |
Fred | Bloggs | 22 |
Ricki | Bobbie | 36 |
Siya | Kolisi | 85 |
3. Dominio
Creiamo lo Spring Data Repository di cui abbiamo bisogno e forniamo la nostra classe di dominio e il tipo di ID.
Per cominciare, abbiamo modellato il nostro Passeggero come un'entità JPA:
@Entity class Passenger { @Id @GeneratedValue @Column(nullable = false) private Long id; @Basic(optional = false) @Column(nullable = false) private String firstName; @Basic(optional = false) @Column(nullable = false) private String lastName; @Basic(optional = false) @Column(nullable = false) private int seatNumber; // constructor, getters etc. }
Invece di usare JPA, avremmo potuto modellarlo come un'altra astrazione.
4. Query tramite API di esempio
In primo luogo, diamo un'occhiata all'interfaccia di JpaRepository . Come possiamo vedere, estende l' interfaccia QueryByExampleExecutor per supportare la query per esempio:
public interface JpaRepository extends PagingAndSortingRepository, QueryByExampleExecutor {}
Questa interfaccia introduce più varianti del metodo find () che abbiamo familiarità con Spring Data. Tuttavia, ogni metodo accetta anche un'istanza di Example :
public interface QueryByExampleExecutor { Optional findOne(Example var1); Iterable findAll(Example var1); Iterable findAll(Example var1, Sort var2); Page findAll(Example var1, Pageable var2); long count(Example var1); boolean exists(Example var1); }
In secondo luogo, l' interfaccia Example espone i metodi per accedere al probe e al ExampleMatcher .
È importante rendersi conto che la sonda è l'istanza della nostra Entità :
public interface Example { static org.springframework.data.domain.Example of(T probe) { return new TypedExample(probe, ExampleMatcher.matching()); } static org.springframework.data.domain.Example of(T probe, ExampleMatcher matcher) { return new TypedExample(probe, matcher); } T getProbe(); ExampleMatcher getMatcher(); default Class getProbeType() { return ProxyUtils.getUserClass(this.getProbe().getClass()); } }
In sintesi, la nostra sonda e il nostro ExampleMatcher insieme specificano la nostra query.
5. Limitazioni
Come tutte le cose, l'API Query by Example ha alcune limitazioni. Per esempio:
- Le istruzioni di annidamento e raggruppamento non sono supportate, ad esempio: ( firstName =? 0 e lastName =? 1) o seatNumber =? 2
- La corrispondenza delle stringhe include solo esatta, senza distinzione tra maiuscole e minuscole, inizia, finisce, contiene e regex
- Tutti i tipi diversi da String sono solo a corrispondenza esatta
Ora che abbiamo un po 'più di familiarità con l'API e i suoi limiti, esaminiamo alcuni esempi.
6. Esempi
6.1. Corrispondenza case-sensitive
Cominciamo con un semplice esempio e parliamo del comportamento predefinito:
@Test public void givenPassengers_whenFindByExample_thenExpectedReturned() { Example example = Example.of(Passenger.from("Fred", "Bloggs", null)); Optional actual = repository.findOne(example); assertTrue(actual.isPresent()); assertEquals(Passenger.from("Fred", "Bloggs", 22), actual.get()); }
In particular, the static Example.of() method builds an Example using ExampleMatcher.matching().
In other words, an exact match will be performed on all non-null properties of Passenger. Thus, the matching is case-sensitive on String properties.
However, it wouldn't be too useful if all we could do was an exact match on all non-null properties.
This is where the ExampleMatcher comes in. By building our own ExampleMatcher, we can customize the behavior to suit our needs.
6.2. Case-Insensitive Matching
With that in mind, let's have a look at another example, this time using withIgnoreCase() to achieve case-insensitive matching:
@Test public void givenPassengers_whenFindByExampleCaseInsensitiveMatcher_thenExpectedReturned() { ExampleMatcher caseInsensitiveExampleMatcher = ExampleMatcher.matchingAll().withIgnoreCase(); Example example = Example.of(Passenger.from("fred", "bloggs", null), caseInsensitiveExampleMatcher); Optional actual = repository.findOne(example); assertTrue(actual.isPresent()); assertEquals(Passenger.from("Fred", "Bloggs", 22), actual.get()); }
In this example, notice that we first called ExampleMatcher.matchingAll() – it has the same behavior as ExampleMatcher.matching(), which we used in the previous example.
6.3. Custom Matching
We can also tune the behavior of our matcher on a per-property basis and match any property using ExampleMatcher.matchingAny():
@Test public void givenPassengers_whenFindByExampleCustomMatcher_thenExpectedReturned() { Passenger jill = Passenger.from("Jill", "Smith", 50); Passenger eve = Passenger.from("Eve", "Jackson", 95); Passenger fred = Passenger.from("Fred", "Bloggs", 22); Passenger siya = Passenger.from("Siya", "Kolisi", 85); Passenger ricki = Passenger.from("Ricki", "Bobbie", 36); ExampleMatcher customExampleMatcher = ExampleMatcher.matchingAny() .withMatcher("firstName", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase()) .withMatcher("lastName", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase()); Example example = Example.of(Passenger.from("e", "s", null), customExampleMatcher); List passengers = repository.findAll(example); assertThat(passengers, contains(jill, eve, fred, siya)); assertThat(passengers, not(contains(ricki))); }
6.4. Ignoring Properties
On the other hand, we may also only want to query on a subset of our properties.
We achieve this by ignoring some properties using ExampleMatcher.ignorePaths(String… paths):
@Test public void givenPassengers_whenFindByIgnoringMatcher_thenExpectedReturned() { Passenger jill = Passenger.from("Jill", "Smith", 50); Passenger eve = Passenger.from("Eve", "Jackson", 95); Passenger fred = Passenger.from("Fred", "Bloggs", 22); Passenger siya = Passenger.from("Siya", "Kolisi", 85); Passenger ricki = Passenger.from("Ricki", "Bobbie", 36); ExampleMatcher ignoringExampleMatcher = ExampleMatcher.matchingAny() .withMatcher("lastName", ExampleMatcher.GenericPropertyMatchers.startsWith().ignoreCase()) .withIgnorePaths("firstName", "seatNumber"); Example example = Example.of(Passenger.from(null, "b", null), ignoringExampleMatcher); List passengers = repository.findAll(example); assertThat(passengers, contains(fred, ricki)); assertThat(passengers, not(contains(jill)); assertThat(passengers, not(contains(eve)); assertThat(passengers, not(contains(siya)); }
7. Conclusione
In questo articolo, abbiamo dimostrato come utilizzare l'API Query by Example.
Abbiamo dimostrato come utilizzare Example e ExampleMatcher insieme all'interfaccia QueryByExampleExecutor per eseguire query su una tabella utilizzando un'istanza di dati di esempio.
In conclusione, puoi trovare il codice su GitHub.