membersound
membersound

Reputation: 86757

Query-by-example skip primitives?

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

Upvotes: 7

Views: 2868

Answers (3)

Kevin Kent
Kevin Kent

Reputation: 9

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:)

Upvotes: 1

U_R_Naveen UR_Naveen
U_R_Naveen UR_Naveen

Reputation: 788

In Spring boot, i was getting primitives as 0. so i have solved as below

     ExampleMatcher matcher = ExampleMatcher.matching().withIgnorePaths("parentId");//ignore primitives
     Example<ConfigMetadata> configExample = Example.of(config, matcher);
     if(config.getParentId()!=null && config.getParentId() != 0) { //if primitives other than null/zero, create new example which includes them
        configExample.getProbe().setParentId(config.getParentId());
        configExample = Example.of(configExample.getProbe());
     }

Upvotes: 0

Mykola Yashchenko
Mykola Yashchenko

Reputation: 5371

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);

Upvotes: 8

Related Questions