Consulta JPA de dados da primavera por exemplo
1. Introdução
Neste tutorial, vamoslearn how to query data with the Spring Data Query by Example API.
Primeiro, vamos definir o esquema dos dados que queremos consultar. A seguir, examinaremos algumas das classes relevantes do Spring Data. E então, veremos alguns exemplos.
Vamos começar!
2. Os dados de teste
Nossos dados de teste são uma lista de nomes de passageiros, bem como o assento que ocupavam.
Primeiro nome |
Último nome |
Número do assento |
Jill |
Smith |
50 |
Eve |
Jackson |
94 |
Fred |
Bloggs |
22 |
Ricki |
Bobbie |
36 |
Siya |
Kolisi |
85 |
3. Domínio
Vamos criar osSpring Data Repository de que precisamos e fornecer nossa classe de domínio e tipo de id.
Para começar, modelamos nossoPassenger como uma entidade 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.
}
Em vez de usar JPA, poderíamos ter modelado como outra abstração.
4. API de consulta por exemplo
Em primeiro lugar, vamos dar uma olhada na interfaceJpaRepository. Como podemos ver, ele estende a interfaceQueryByExampleExecutor para oferecer suporte a consultas por exemplo:
public interface JpaRepository
extends PagingAndSortingRepository, QueryByExampleExecutor {}
Esta interface apresenta mais variantes do métodofind() com o qual estamos familiarizados no Spring Data. No entanto, cada método também aceita uma instância deExample:
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);
}
Em segundo lugar, a interfaceExample expõe métodos para acessarprobeeExampleMatcher.
É importante perceber queprobe é a instância de nossoEntity:
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());
}
}
Em resumo, nossoprobe e nossoExampleMatcher juntos especificam nossa consulta.
5. Limitações
Como tudo, a API Query by Example tem algumas limitações. Por exemplo:
-
As instruções de aninhamento e agrupamento não são suportadas, por exemplo:(firstName= ?0 and lastName= ?1) orseatNumber= ?2
-
A correspondência de cadeias inclui apenas letras maiúsculas e minúsculas exatas, inicia, termina, contém e regex
-
Todos os tipos diferentes deString são apenas de correspondência exata
Agora que estamos um pouco mais familiarizados com a API e suas limitações, vamos mergulhar em alguns exemplos.
6. Exemplos
6.1. Correspondência que diferencia maiúsculas de minúsculas
Vamos começar com um exemplo simples e falar sobre o comportamento padrão:
@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());
}
Em particular, o métodoExample.of() estático constrói umExample usandoExampleMatcher.matching().
Em outras palavras,an exact match will be performed on all non-null properties dePassenger. Portanto, a correspondência diferencia maiúsculas de minúsculas nas propriedades deString.
No entanto, não seria muito útil se tudo o que pudéssemos fazer fosse uma correspondência exata em todas as propriedades não nulas.
É aqui que entra oExampleMatcher. Ao construir nosso próprioExampleMatcher, podemos personalizar o comportamento para atender às nossas necessidades.
6.2. Correspondência que não diferencia maiúsculas de minúsculas
Com isso em mente, vamos dar uma olhada em outro exemplo, desta vez usandowithIgnoreCase() para obter correspondência que não diferencia maiúsculas de minúsculas:
@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());
}
Neste exemplo, observe que chamamos primeiroExampleMatcher.matchingAll() –, ele tem o mesmo comportamento queExampleMatcher.matching(), que usamos no exemplo anterior.
6.3. Correspondência personalizada
Também podemostune the behavior of our matcher on a per-property basise corresponder a qualquer propriedade usandoExampleMatcher.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. Ignorando propriedades
Por outro lado, também podemos querer apenasquery on a subset of our properties.
Conseguimos isso ignorando algumas propriedades usandoExampleMatcher.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. Conclusão
Neste artigo, demonstramos como usar a API Query by Example.
Demonstramos como usarExampleeExampleMatcher junto com a interfaceQueryByExampleExecutor para consultar uma tabela usando uma instância de dados de exemplo.
Concluindo, você pode encontrar o códigoover on GitHub.