Query JPA sui dati di primavera per esempio

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.