Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Data JPA ignore null parameter

Say i have the below JPA method :

public List<FrequencyCode> findAllByNameContainingAndAllowExplicitDosingTimesEqualsOrderByName(String name, Boolean allowExplicitDosingTimes);

This method is called by a user filtering a list of these objects with an input field and a select field :

enter image description here

The boolean value can be true, false or null in this case if the user is not making a search with that field. It looks like JPA is ACTUALLY searching for a null value when i would like it to ignore any null values. I have been able to make this combined search work with the below code :

@Override
public List<FrequencyCode> findAllWithFilters(String name, Boolean allowExplicitDosingTimes) 
{
    if (allowExplicitDosingTimes == null)
    {
        return ((FrequencyCodeRepository) baseRepository).findAllByNameContainingOrderByName(name);
    }
    else if (allowExplicitDosingTimes == true)
    {
        return ((FrequencyCodeRepository) baseRepository).findAllByNameContainingAndAllowExplicitDosingTimesTrueOrderByName(name);
    }
    else if (allowExplicitDosingTimes == false)
    {
        return ((FrequencyCodeRepository) baseRepository).findAllByNameContainingAndAllowExplicitDosingTimesFalseOrderByName(name);
    }

    return null;
}

This works but, obviously, on a page with 8 search options this would become a nightmare. The String parameters do not have this problem because they are actually an empty String when the user doesn't choose a filter. This paired with the Containing keyword, any value contains "" so it behaves as if that parameter is ignored which is exactly what I want for other types. Is there a way for a JPA findAll...() method to simply ignore null parameters?

******SOLUTION******

Here is how i made this work with the help of the accepted answer :

FrequencyCode fc = new FrequencyCode();
    fc.setName(name);
    fc.setAllowExplicitDosingTimes(allowExplicitDosingTimes);

    ExampleMatcher matcher = ExampleMatcher.matching()
        .withMatcher("name", match -> match.contains())
        .withMatcher("allowExplicitDosingTimes", match -> match.exact())
        .withIgnorePaths("id", "uuid")
        .withIgnoreNullValues();
    Example<FrequencyCode> example = Example.of(fc, matcher);

    List<FrequencyCode> frequencyCodes = ((FrequencyCodeRepository) baseRepository).findAll(example);

You HAVE to tell it to ignore any ID fields or really any other fields you do not intend to search with but this is INCREDIBLY powerful!

Thanks!

like image 294
Martin Avatar asked Oct 16 '22 07:10

Martin


1 Answers

You can use Example like this

@Override
public List<FrequencyCode> findAllWithFilters(String name, Boolean allowExplicitDosingTimes) {

  FrequencyCode fc = new FrequencyCode();         
  //I assume that you have setters like bellow                 
  fc.setName(name);
  fc.setAllowExplicitDosingTimes(allowExplicitDosingTimes);                           

  ExampleMatcher matcher = ExampleMatcher.matching().withIgnoreNullValues();                        

  Example<FrequencyCode> example = Example.of(fc, matcher);

  return ((FrequencyCodeRepository) baseRepository).findAll(example);
}
like image 59
Saša Šijak Avatar answered Oct 21 '22 00:10

Saša Šijak