Spring supports creating queries by examples of the object to look for. Like:
//if not setting the age, it will always look for age=0
Person p = new Person();
p.setLastName("Smith");
List<Person> foundPersons = personRepository.findAll(Example.of(p));
@Entity
public class Person {
private String firstName;
private String lastName;
private LocalDate dob;
private int age;
}
Problem: if the @Entity
has primitive fields, then their default value will actually be used for creating the query. The example above will result in:
SELECT * from persons where lastname := 'Smith' and age := 0
In my example I have a database field where age
must always be filled, thus is not allowed to be null
. Therefore the entity has a primitive int age
field.
Of course I could now change the field to Integer age
, but then I'd marking the field being an optional nullable attribute, which is not true.
So, how can I skip primitives that have not been set on the Example
?
Reference Example
Yes, you can do it:
Person p = new Person();
p.setLastName("Smith");
Example criteria = Example.create(p).setPropertySelector(
Example.NotNullOrZeroPropertySelector.INSTANCE
);
List<Person> foundPersons = session.createCriteria(Person.class).add(criteria).list();
Example.NotNullOrZeroPropertySelector.INSTANCE
is a property selector that includes only properties that are not null
and non-zero (if numeric)
UPD
Above an example for Hibernate org.hibernate.criterion.Example
class. For org.springframework.data.domain.Example
you can ignore primitive fields by manually specifying names of these fields:
Person p = new Person();
p.setLastName("Smith");
ExampleMatcher matcher = ExampleMatcher.matching().withIgnorePaths("age").withIgnoreNullValues();
Example criteria = Example.of(p, matcher);
List<Person> foundPersons = personRepository.findAll(criteria);
I use reactive java and spring data. Here is repository:
public interface MyObjectRepository extends ReactiveCrudRepository<MyObject, Long>, ReactiveQueryByExampleExecutor<MyObject> {}
Service:
public Mono<Page<MyObject>> getAllBySupport(Pageable pageable, Boolean isSupported) {
ExampleMatcher m;
Example<MyObject> ex;
if (isSupported != null) {
m = ExampleMatcher.matching().withIgnoreNullValues();
ex = Example.of(MyObject.builder().isSupport(isSupported).build(), m);
} else {
//isSupport field in Myobject has boolean primitive type
//if parameter isSupported is null - I ignore this parameter in example
//and result has objects with true and false isSupport field
m = ExampleMatcher.matching().withIgnorePaths("isSupport").withIgnoreNullValues();
ex = Example.of(new MyObject(), m);
}
return myObjectRepository.findBy(ex, (p) -> p.page(pageable))
.map(s -> new PageImpl<>(s.stream()
.collect(Collectors.toList()), pageable, s.getTotalElements()));
With this code you also can hava pagination and sorting
Wish you luck:)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With