Query by Example (QBE) builds repository predicates from an example domain object rather than a query-language expression. It combines a probe, an ExampleMatcher, and an Example; the matcher defines property rules, and the Example packages both for query generation. section 4.10 section 17.4
Use QBE when:
- Decoupling application code from the underlying data-store API. section 4.10
- Accommodating frequent domain-object structure changes without revising existing queries. section 4.10
- Representing static or dynamic repository constraints through reusable matching rules. section 4.10
Matching email suffixes
Create a User probe with email set to "@someotherdomain.com". Configure ExampleMatcher.matching() to ignore "level" and "active" and match email with endsWith(). Pass Example.of(user, matcher) to userRepository.findAll(example); the generated SQL uses an email LIKE predicate.
Null reference properties are ignored, but primitive properties require explicit ignore paths. Leaving defaults such as active and level included adds conditions that can change results. String properties support starting, ending, containing, and regex matching; other types use exact matching. Nested or grouped property constraints are not supported. section 17.4 section 4.10
Listing 4.22 Query By Example tests
Path: Ch04/springdatajpa2/src/test/java/com/manning/javapersistence /springdatajpa/QueryByExampleTest.java public class QueryByExampleTest extends SpringDataJpaApplicationTests { @Test void testEmailWithQueryByExample() { User user = new User(); #1 user.setEmail("@someotherdomain.com"); #1 ExampleMatcher matcher = ExampleMatcher.matching() #2 .withIgnorePaths("level", "active") #2 .withMatcher("email", match -> match.endsWith()); #2 Example<User> example = Example.of(user, matcher); #3 List<User> users = userRepository.findAll(example); #4 assertEquals(4, users.size()); #5 } @Test void testUsernameWithQueryByExample() { User user = new User(); #6 user.setUsername("J"); #6 ExampleMatcher matcher = ExampleMatcher.matching() #7 .withIgnorePaths("level", "active") #7 .withStringMatcher(ExampleMatcher.StringMatcher.STARTING) #7 .withIgnoreCase(); #7 Example<User> example = Example.of(user, matcher); #8 List<User> users = userRepository.findAll(example); #9 assertEquals(3, users.size()); #10 } } #1 Initialize a <kbd>User</kbd> instance and set up an <kbd>email</kbd> for it. This will represent the probe. #2 Create the <kbd>ExampleMatcher</kbd> with the help of the builder pattern. Any <kbd>null</kbd> reference property will be ignored by the matcher. However, we need to explicitly ignore the <kbd>level</kbd> and <kbd>active</kbd> properties, which are primitives. If they were not ignored, they would be included in the matcher with their default values (0 for <kbd>level</kbd> and <kbd>false</kbd> for <kbd>active</kbd>) and would change the generated query. We’ll configure the matcher condition so that the <kbd>email</kbd> property will end with a given string. #3 Create an <kbd>Example</kbd> that puts the probe and <kbd>ExampleMatcher</kbd> together and generates the query. The query will search for users that have an <kbd>email</kbd> property ending with the string defining the <kbd>email</kbd> of the probe. #4 Execute the query to find all users matching the probe. #5 Verify that there are four users of this kind. #6 Initialize a <kbd>User</kbd> instance and set up a <kbd>name</kbd> for it. This will represent the second probe. #7 Create the <kbd>ExampleMatcher</kbd> with the help of the builder pattern. Any <kbd>null</kbd> reference property will be ignored by the matcher. Again, we need to explicitly ignore the <kbd>level</kbd> and <kbd>active</kbd> properties, which are primitives. We configure the matcher condition so that the match will be made on starting strings for the configured properties (the <kbd>username</kbd> property from the probe, in our case). #8 Create an <kbd>Example</kbd> that puts the probe and the <kbd>ExampleMatcher</kbd> together and generates the query. The query will search for users having a <kbd>username</kbd> property that starts with the string defining the <kbd>username</kbd> of the probe. #9 Execute the query to find all users matching the probe. #10 Verify that there are six users of this kind.
Shows a complete Spring Data JPA test that constructs a probe, configures an ExampleMatcher, creates an Example, executes the repository query, and verifies the result count. section 4.10
