Skip to content

Commit 4af84b0

Browse files
committed
DATAJPA-218 - Add documentation for Query by Example.
1 parent 7b26959 commit 4af84b0

File tree

2 files changed

+149
-2
lines changed

2 files changed

+149
-2
lines changed

src/main/asciidoc/index.adoc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
= Spring Data JPA - Reference Documentation
2-
Oliver Gierke; Thomas Darimont; Christoph Strobl
2+
Oliver Gierke; Thomas Darimont; Christoph Strobl; Mark Paluch
33
:revnumber: {version}
44
:revdate: {localdate}
55
:toc:
66
:toc-placement!:
77
:spring-data-commons-docs: ../../../../spring-data-commons/src/main/asciidoc
88
:spring-framework-docs: http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html
99

10-
(C) 2008-2015 The original authors.
10+
(C) 2008-2016 The original authors.
1111

1212
NOTE: Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.
1313

@@ -24,6 +24,7 @@ include::{spring-data-commons-docs}/repositories.adoc[]
2424

2525
:leveloffset: +1
2626
include::jpa.adoc[]
27+
include::query-by-example.adoc[]
2728
:leveloffset: -1
2829

2930
[[appendix]]
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
[[query.by.example]]
2+
= Query by Example
3+
4+
== Introduction
5+
6+
This chapter will give you an introduction to Query by Example and explain how to use example specifications.
7+
8+
Query by Example (QBE) is a user-friendly querying technique with a simple interface. It allows dynamic query creation and does not require to write queries containing field names. In fact, Query by Example does not require to write queries using store-specific query languages at all.
9+
10+
== Usage
11+
12+
An `Example` takes a data object (usually the entity object or a subtype of it) and a specification how to match properties. You can use Query by Example with Repositories.
13+
14+
Query by Example is suited for several use-cases but also comes with limitations:
15+
16+
**When to use**
17+
18+
* Querying your data store with a set of static or dynamic constraints
19+
* Frequent refactoring of the entities without worrying about breaking existing queries
20+
* Works independently from the data store API
21+
22+
**Limitations**
23+
24+
* Query predicates are combined using the `AND` keyword
25+
* No support for nested/grouped property constraints like `firstname = ?0 or (firstname = ?1 and lastname = ?2)`
26+
* Only supports starts/contains/ends/regex matching for strings and exact matching for other property types
27+
28+
29+
Before getting started with Query by Example you need to have your interface to the data store set up.
30+
31+
.Sample Person object
32+
====
33+
[source,java]
34+
----
35+
@Entity
36+
public class Person {
37+
38+
@Id
39+
private String id;
40+
private String firstname;
41+
private String lastname;
42+
private Address address;
43+
44+
// … getters and setters omitted
45+
}
46+
----
47+
====
48+
49+
This is a simple entity. You can use it to create an Example specification. By default, fields having `null` values are ignored, and strings are matched using the store specific defaults. Examples can be built by either using the `exampleOf` factory method or by using the <<query.by.example.builder,Example builder>>. Once the `Example` is constructed it becomes immutable.
50+
51+
.Simple Example specification
52+
====
53+
[source,xml]
54+
----
55+
Person person = new Person(); <1>
56+
57+
person.setFirstname("Dave"); <2>
58+
59+
Example<Person> example = Example.exampleOf(person); <3>
60+
----
61+
<1> Create a new instance of the entity
62+
<2> Set the properties to query
63+
<3> Create an `Example`
64+
====
65+
66+
67+
NOTE: Property names of the sample object must correlate with the property names of the queried entity.
68+
69+
.Query by Example using a Repository
70+
====
71+
[source, java]
72+
----
73+
public interface JpaRepository<Person, String> {
74+
75+
List<Person> findAllByExample(Example<Person> example);
76+
77+
List<Person> findAllByExample(Example<Person> example, Sort sort);
78+
79+
Page<Person> findAllByExample(Example<Person> example, Pageable pageable);
80+
81+
// … more functionality omitted.
82+
}
83+
----
84+
====
85+
86+
[[query.by.example.builder]]
87+
== Example builder
88+
89+
Examples are not limited to default settings. You can specify own defaults for string matching, null handling and property-specific settings using the example builder.
90+
91+
.Query by Example builder
92+
====
93+
[source, java]
94+
----
95+
Example.newExampleOf(person)
96+
.withStringMatcher(StringMatcher.ENDING)
97+
.includeNullValues()
98+
.withPropertySpecifier(
99+
newPropertySpecifier("firstname").matchString(StringMatcher.CONTAINING).get())
100+
.withPropertySpecifier(
101+
newPropertySpecifier("lastname").matchStringsWithIgnoreCase().get())
102+
.withPropertySpecifier(
103+
newPropertySpecifier("address.city").matchStringStartingWith().get())
104+
.get();
105+
----
106+
====
107+
108+
Property specifier accepts property names (e.g. "firstname" and "lastname"). You can navigate by chaining properties together with dots ("address.city"). You can tune it with matching options and case sensitivity.
109+
110+
[cols="1,2", options="header"]
111+
.`StringMatcher` options
112+
|===
113+
| Matching
114+
| Logical result
115+
116+
| `DEFAULT` (case-sensitive)
117+
| `firstname = ?0`
118+
119+
| `DEFAULT` (case-insensitive)
120+
| `LOWER(firstname) = LOWER(?0)`
121+
122+
| `EXACT` (case-sensitive)
123+
| `firstname = ?0`
124+
125+
| `EXACT` (case-insensitive)
126+
| `LOWER(firstname) = LOWER(?0)`
127+
128+
| `STARTING` (case-sensitive)
129+
| `firstname like ?0 + '%'`
130+
131+
| `STARTING` (case-insensitive)
132+
| `LOWER(firstname) like LOWER(?0) + '%'`
133+
134+
| `ENDING` (case-sensitive)
135+
| `firstname like '%' + ?0`
136+
137+
| `ENDING` (case-insensitive)
138+
| `LOWER(firstname) like '%' + LOWER(?0)`
139+
140+
| `CONTAINING` (case-sensitive)
141+
| `firstname like '%' + ?0 + '%'`
142+
143+
| `CONTAINING` (case-insensitive)
144+
| `LOWER(firstname) like '%' + LOWER(?0) + '%'`
145+
146+
|===

0 commit comments

Comments
 (0)